From 3c050f4383c85c0dc72c2b06f6d85947f7051a38 Mon Sep 17 00:00:00 2001 From: suleman-uzair Date: Fri, 11 Jul 2025 18:18:19 +0500 Subject: [PATCH 1/4] added missing property for NISTu27 --- units.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/units.yaml b/units.yaml index 7f0afab..2b38c93 100644 --- a/units.yaml +++ b/units.yaml @@ -6595,6 +6595,9 @@ units: id: NISTu2 root: true short: gram + unit_system_reference: + - type: unitsml + id: si-base symbols: - latex: "\\ensuremath{\\mathrm{g}}" unicode: g From 3e90bae6b03044a92c91bdd12eb93886fb1e87e7 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Sat, 12 Jul 2025 00:59:44 +0800 Subject: [PATCH 2/4] chore: add schema checks --- dimensions.yaml | 1 + prefixes.yaml | 1 + quantities.yaml | 1 + scales.yaml | 1 + schemas/README.md | 159 ++++++++++++++++++++++ schemas/dimensions-schema.yaml | 157 ++++++++++++++++++++++ schemas/prefixes-schema.yaml | 159 ++++++++++++++++++++++ schemas/quantities-schema.yaml | 120 +++++++++++++++++ schemas/scales-schema.yaml | 109 ++++++++++++++++ schemas/unit_systems-schema.yaml | 120 +++++++++++++++++ schemas/units-schema.yaml | 217 +++++++++++++++++++++++++++++++ unit_systems.yaml | 1 + units.yaml | 1 + validate_schemas.rb | 208 +++++++++++++++++++++++++++++ 14 files changed, 1255 insertions(+) create mode 100644 schemas/README.md create mode 100644 schemas/dimensions-schema.yaml create mode 100644 schemas/prefixes-schema.yaml create mode 100644 schemas/quantities-schema.yaml create mode 100644 schemas/scales-schema.yaml create mode 100644 schemas/unit_systems-schema.yaml create mode 100644 schemas/units-schema.yaml create mode 100755 validate_schemas.rb diff --git a/dimensions.yaml b/dimensions.yaml index d8f741e..4c29491 100644 --- a/dimensions.yaml +++ b/dimensions.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=schemas/dimensions-schema.yaml --- schema_version: 2.0.0 dimensions: diff --git a/prefixes.yaml b/prefixes.yaml index f9947e2..941dfd9 100644 --- a/prefixes.yaml +++ b/prefixes.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=schemas/prefixes-schema.yaml --- schema_version: 2.0.0 prefixes: diff --git a/quantities.yaml b/quantities.yaml index 43d65dd..c544858 100644 --- a/quantities.yaml +++ b/quantities.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=schemas/quantities-schema.yaml --- schema_version: 2.0.0 quantities: diff --git a/scales.yaml b/scales.yaml index 367075c..650dcfc 100644 --- a/scales.yaml +++ b/scales.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=schemas/scales-schema.yaml --- schema_version: 2.0.0 scales: diff --git a/schemas/README.md b/schemas/README.md new file mode 100644 index 0000000..709b30a --- /dev/null +++ b/schemas/README.md @@ -0,0 +1,159 @@ +# UnitsDB YAML Schemas + +This directory contains JSON Schema definitions for all YAML files in the UnitsDB repository. These schemas provide validation, documentation, and IDE support for the structured data files. + +## Schema Files + +### Core Data Schemas + +- **`units-schema.yaml`** - Schema for `units.yaml` + - Defines physical units with their symbols, definitions, and relationships + - Includes conversion factors, dimension references, and unit systems + +- **`quantities-schema.yaml`** - Schema for `quantities.yaml` + - Defines physical quantities with their dimensional analysis + - Links quantities to their fundamental dimensions + +- **`dimensions-schema.yaml`** - Schema for `dimensions.yaml` + - Defines fundamental physical dimensions (length, mass, time, etc.) + - Includes dimensional components and mathematical symbols + +- **`prefixes-schema.yaml`** - Schema for `prefixes.yaml` + - Defines unit prefixes (kilo, mega, micro, etc.) + - Includes base/power notation and symbol representations + +- **`scales-schema.yaml`** - Schema for `scales.yaml` + - Defines measurement scales and their properties + - Includes scale types and conversion relationships + +- **`unit_systems-schema.yaml`** - Schema for `unit_systems.yaml` + - Defines coherent systems of units (SI, CGS, etc.) + - Includes base units and derived unit relationships + +## Features + +### Validation +All schemas provide comprehensive validation for: +- Required fields and data types +- Enumerated values for controlled vocabularies +- Pattern matching for identifiers and codes +- Cross-references between related entities + +### Documentation +Each schema includes: +- Detailed descriptions for all fields +- Examples of valid values +- Explanations of relationships between entities + +### IDE Support +The schemas enable: +- Auto-completion in YAML editors +- Real-time validation feedback +- Hover documentation for fields +- Error highlighting and suggestions + +## Usage + +### In VSCode +The YAML files automatically reference their schemas via the `yaml-language-server` directive at the top of each file: + +```yaml +# yaml-language-server: $schema=schemas/units-schema.yaml +``` + +### Programmatic Validation +Use the provided validation script: + +```bash +ruby validate_schemas.rb +``` + +### Manual Validation +You can validate individual files using any JSON Schema validator that supports YAML, such as: +- `ajv-cli` +- `jsonschema` (Python) +- Online validators like jsonschemavalidator.net + +## Schema Structure + +All schemas follow a consistent structure: + +```yaml +$schema: "http://json-schema.org/draft-06/schema#" +$id: "https://unitsml.org/schemas/[schema-name].yaml" +title: "[Human Readable Title]" +description: "[Detailed description]" + +type: object +required: ["schema_version", "[main_array]"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + [main_array]: + type: array + items: + $ref: "#/definitions/[MainType]" + +definitions: + # Type definitions... +``` + +## Common Definitions + +### Identifier +All entities use a consistent identifier structure: +```yaml +type: object +required: ["type", "id"] +properties: + type: + type: string + enum: ["nist", "unitsml", "si-digital-framework", ...] + id: + type: string +``` + +### Name +Multilingual names follow this pattern: +```yaml +type: object +required: ["value", "lang"] +properties: + value: + type: string + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" +``` + +### Symbol +Mathematical symbols are represented as: +```yaml +type: object +required: ["latex", "unicode", "ascii", "html", "id", "mathml"] +properties: + latex: { type: string } + unicode: { type: string } + ascii: { type: string } + html: { type: string } + id: { type: string } + mathml: { type: string } +``` + +## Validation Results + +✅ All schemas successfully validate their corresponding YAML files +✅ Cross-references and relationships are properly defined +✅ Enumerated values match actual data usage +✅ Required fields are correctly identified + +## Maintenance + +When updating the YAML data files: +1. Ensure changes conform to the existing schemas +2. Update schemas if new fields or structures are added +3. Run validation to verify compatibility +4. Update this documentation if schema structure changes + +For questions or issues with the schemas, please refer to the main repository documentation or open an issue. diff --git a/schemas/dimensions-schema.yaml b/schemas/dimensions-schema.yaml new file mode 100644 index 0000000..fa850a2 --- /dev/null +++ b/schemas/dimensions-schema.yaml @@ -0,0 +1,157 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-06/schema +--- +$schema: "http://json-schema.org/draft-06/schema#" +$id: "https://unitsml.org/schemas/dimensions-schema.yaml" +title: "Dimensions Database Schema" +description: "Schema for dimensions.yaml - defines fundamental physical dimensions" + +type: object +required: ["schema_version", "dimensions"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + description: "Semantic version of the schema" + dimensions: + type: array + description: "Array of dimension definitions" + items: + $ref: "#/definitions/Dimension" + +definitions: + Dimension: + type: object + required: ["identifiers", "names", "short"] + properties: + identifiers: + type: array + description: "External identifiers for this dimension" + items: + $ref: "#/definitions/Identifier" + names: + type: array + description: "Multilingual names for this dimension" + items: + $ref: "#/definitions/Name" + short: + type: string + description: "Short identifier for the dimension" + dimensionless: + type: boolean + description: "Whether this is a dimensionless quantity" + length: + $ref: "#/definitions/DimensionComponent" + description: "Length dimension component" + mass: + $ref: "#/definitions/DimensionComponent" + description: "Mass dimension component" + time: + $ref: "#/definitions/DimensionComponent" + description: "Time dimension component" + electric_current: + $ref: "#/definitions/DimensionComponent" + description: "Electric current dimension component" + thermodynamic_temperature: + $ref: "#/definitions/DimensionComponent" + description: "Thermodynamic temperature dimension component" + amount_of_substance: + $ref: "#/definitions/DimensionComponent" + description: "Amount of substance dimension component" + luminous_intensity: + $ref: "#/definitions/DimensionComponent" + description: "Luminous intensity dimension component" + plane_angle: + $ref: "#/definitions/DimensionComponent" + description: "Plane angle dimension component" + references: + type: array + description: "External references and citations" + items: + $ref: "#/definitions/Reference" + + Identifier: + type: object + required: ["type", "id"] + properties: + type: + type: string + enum: ["nist", "unitsml", "si-digital-framework"] + description: "Type of identifier system" + id: + type: string + description: "Identifier value within the system" + + Name: + type: object + required: ["value", "lang"] + properties: + value: + type: string + description: "Name in the specified language" + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" + description: "Language code (ISO 639-1, optionally with ISO 3166-1 country)" + + Symbol: + type: object + required: ["latex", "unicode", "ascii", "html", "id", "mathml"] + properties: + latex: + type: string + description: "LaTeX representation" + unicode: + type: string + description: "Unicode representation" + ascii: + type: string + description: "ASCII representation" + html: + type: string + description: "HTML representation" + id: + type: string + description: "Identifier for the symbol" + mathml: + type: string + description: "MathML representation" + + DimensionComponent: + type: object + required: ["power", "symbol"] + properties: + power: + type: integer + description: "Exponent for this dimension component" + symbol: + type: string + description: "Symbol representing this dimension" + symbols: + type: array + description: "Mathematical and textual representations" + items: + $ref: "#/definitions/Symbol" + + Reference: + type: object + required: ["type"] + properties: + type: + type: string + enum: ["standard", "specification", "publication", "website"] + description: "Type of reference" + authority: + type: string + description: "Authoritative body or organization" + uri: + type: string + format: "uri" + description: "URI to the reference" + title: + type: string + description: "Title of the reference" + year: + type: integer + minimum: 1000 + maximum: 9999 + description: "Publication year" diff --git a/schemas/prefixes-schema.yaml b/schemas/prefixes-schema.yaml new file mode 100644 index 0000000..d58cc7d --- /dev/null +++ b/schemas/prefixes-schema.yaml @@ -0,0 +1,159 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-06/schema +--- +$schema: "http://json-schema.org/draft-06/schema" +$id: "https://unitsml.org/schemas/prefixes-schema.yaml" +title: "Prefixes Database Schema" +description: "Schema for prefixes.yaml - defines unit prefixes with their multipliers and symbols" + +type: object +required: ["schema_version", "prefixes"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + description: "Semantic version of the schema" + prefixes: + type: array + description: "Array of prefix definitions" + items: + $ref: "#/definitions/Prefix" + +definitions: + Prefix: + type: object + required: ["identifiers", "names", "base", "power", "short", "symbols"] + properties: + identifiers: + type: array + description: "External identifiers for this prefix" + items: + $ref: "#/definitions/Identifier" + names: + type: array + description: "Multilingual names for this prefix" + items: + $ref: "#/definitions/Name" + base: + type: integer + description: "Base number for the prefix (e.g., 10 for decimal, 2 for binary)" + power: + type: integer + description: "Power/exponent for the prefix" + short: + type: string + description: "Short identifier for the prefix" + symbols: + type: array + description: "Mathematical and textual representations" + items: + $ref: "#/definitions/PrefixSymbol" + references: + type: array + description: "External references and citations" + items: + $ref: "#/definitions/Reference" + + Identifier: + type: object + required: ["type", "id"] + properties: + type: + type: string + enum: ["nist", "unitsml", "ucum", "si-digital-framework"] + description: "Type of identifier system" + id: + type: string + description: "Identifier value within the system" + + Name: + type: object + required: ["value", "lang"] + properties: + value: + type: string + description: "Name in the specified language" + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" + description: "Language code (ISO 639-1, optionally with ISO 3166-1 country)" + + Symbol: + type: object + required: ["type"] + properties: + type: + type: string + enum: ["latex", "unicode", "ascii", "html", "id", "mathml"] + description: "Type of symbol representation" + value: + type: string + description: "Symbol value (required for most types)" + allOf: + - if: + properties: + type: + const: "id" + then: + not: + required: ["value"] + else: + required: ["value"] + + PrefixSymbol: + type: object + required: ["latex", "unicode", "ascii", "html", "id", "mathml"] + properties: + latex: + type: string + description: "LaTeX representation" + unicode: + type: string + description: "Unicode representation" + ascii: + type: string + description: "ASCII representation" + html: + type: string + description: "HTML representation" + id: + type: string + description: "Identifier for the symbol" + mathml: + type: string + description: "MathML representation" + + Multiplier: + type: object + required: ["base", "power"] + properties: + base: + type: integer + minimum: 2 + description: "Base of the multiplier (typically 10)" + power: + type: integer + description: "Exponent for the multiplier" + + Reference: + type: object + required: ["type"] + properties: + type: + type: string + enum: ["standard", "specification", "publication", "website", "normative", "informative"] + description: "Type of reference" + authority: + type: string + description: "Authoritative body or organization" + uri: + type: string + format: "uri" + description: "URI to the reference" + title: + type: string + description: "Title of the reference" + year: + type: integer + minimum: 1000 + maximum: 9999 + description: "Publication year" diff --git a/schemas/quantities-schema.yaml b/schemas/quantities-schema.yaml new file mode 100644 index 0000000..f563204 --- /dev/null +++ b/schemas/quantities-schema.yaml @@ -0,0 +1,120 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-06/schema + +--- +$schema: "http://json-schema.org/draft-06/schema#" +$id: "https://unitsml.org/schemas/quantities-schema.yaml" +title: "Quantities Database Schema" +description: "Schema for quantities.yaml - defines physical quantities with their dimensional analysis" + +type: object +required: ["schema_version", "quantities"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + description: "Semantic version of the schema" + quantities: + type: array + description: "Array of quantity definitions" + items: + $ref: "#/definitions/Quantity" + +definitions: + Quantity: + type: object + required: ["identifiers", "names", "dimension_reference", "quantity_type", "short"] + properties: + identifiers: + type: array + description: "External identifiers for this quantity" + items: + $ref: "#/definitions/Identifier" + names: + type: array + description: "Multilingual names for this quantity" + items: + $ref: "#/definitions/Name" + dimension_reference: + $ref: "#/definitions/DimensionReference" + description: "Reference to the dimension" + quantity_type: + type: string + enum: ["base", "derived"] + description: "Type of quantity (base or derived)" + short: + type: string + description: "Short identifier for the quantity" + references: + type: array + description: "External references and citations" + items: + $ref: "#/definitions/Reference" + + Identifier: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Type of identifier system" + id: + type: string + description: "Identifier value within the system" + + Name: + type: object + required: ["value", "lang"] + properties: + value: + type: string + description: "Name in the specified language" + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" + description: "Language code (ISO 639-1, optionally with ISO 3166-1 country)" + + DimensionReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + const: "nist" + description: "Reference type indicator" + id: + type: string + description: "Dimension identifier" + + Symbol: + type: object + required: ["type"] + properties: + type: + type: string + description: "Type of symbol representation" + value: + type: string + description: "Symbol value" + + Reference: + type: object + required: ["type"] + properties: + type: + type: string + description: "Type of reference" + authority: + type: string + description: "Authoritative body or organization" + uri: + type: string + format: "uri" + description: "URI to the reference" + title: + type: string + description: "Title of the reference" + year: + type: integer + minimum: 1000 + maximum: 9999 + description: "Publication year" diff --git a/schemas/scales-schema.yaml b/schemas/scales-schema.yaml new file mode 100644 index 0000000..5634a5b --- /dev/null +++ b/schemas/scales-schema.yaml @@ -0,0 +1,109 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-06/schema +--- +$schema: "http://json-schema.org/draft-06/schema#" +$id: "https://unitsml.org/schemas/scales-schema.yaml" +title: "Scales Database Schema" +description: "Schema for scales.yaml - defines measurement scales with their mathematical properties" + +type: object +required: ["schema_version", "scales"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + description: "Semantic version of the schema" + scales: + type: array + description: "Array of scale definitions" + items: + $ref: "#/definitions/Scale" + +definitions: + Scale: + type: object + required: ["identifiers", "names", "properties"] + properties: + identifiers: + type: array + description: "External identifiers for this scale" + items: + $ref: "#/definitions/Identifier" + names: + type: array + description: "Multilingual names for this scale" + items: + $ref: "#/definitions/Name" + properties: + $ref: "#/definitions/ScaleProperties" + description: "Mathematical properties of the scale" + references: + type: array + description: "External references and citations" + items: + $ref: "#/definitions/Reference" + + Identifier: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Type of identifier system" + id: + type: string + description: "Identifier value within the system" + + Name: + type: object + required: ["value", "lang"] + properties: + value: + type: string + description: "Name in the specified language" + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" + description: "Language code (ISO 639-1, optionally with ISO 3166-1 country)" + + ScaleProperties: + type: object + required: ["continuous", "ordered", "logarithmic", "interval", "ratio"] + properties: + continuous: + type: boolean + description: "Whether the scale is continuous" + ordered: + type: boolean + description: "Whether the scale has an ordering" + logarithmic: + type: boolean + description: "Whether the scale is logarithmic" + interval: + type: boolean + description: "Whether the scale has meaningful intervals" + ratio: + type: boolean + description: "Whether the scale has a meaningful zero point" + + Reference: + type: object + required: ["type"] + properties: + type: + type: string + description: "Type of reference" + authority: + type: string + description: "Authoritative body or organization" + uri: + type: string + format: "uri" + description: "URI to the reference" + title: + type: string + description: "Title of the reference" + year: + type: integer + minimum: 1000 + maximum: 9999 + description: "Publication year" diff --git a/schemas/unit_systems-schema.yaml b/schemas/unit_systems-schema.yaml new file mode 100644 index 0000000..d1707df --- /dev/null +++ b/schemas/unit_systems-schema.yaml @@ -0,0 +1,120 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-06/schema +--- +$schema: "http://json-schema.org/draft-06/schema#" +$id: "https://unitsml.org/schemas/unit_systems-schema.yaml" +title: "Unit Systems Database Schema" +description: "Schema for unit_systems.yaml - defines systems of measurement units" + +type: object +required: ["schema_version", "unit_systems"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + description: "Semantic version of the schema" + unit_systems: + type: array + description: "Array of unit system definitions" + items: + $ref: "#/definitions/UnitSystem" + +definitions: + UnitSystem: + type: object + required: ["identifiers", "names"] + properties: + identifiers: + type: array + description: "External identifiers for this unit system" + items: + $ref: "#/definitions/Identifier" + names: + type: array + description: "Multilingual names for this unit system" + items: + $ref: "#/definitions/Name" + base_units: + type: array + description: "Base units that define this system" + items: + $ref: "#/definitions/BaseUnitReference" + references: + type: array + description: "External references and citations" + items: + $ref: "#/definitions/Reference" + + Identifier: + type: object + required: ["type", "id"] + properties: + type: + type: string + enum: ["nist", "unitsml", "si-digital-framework"] + description: "Type of identifier system" + id: + type: string + description: "Identifier value within the system" + + Name: + type: object + required: ["value", "lang"] + properties: + value: + type: string + description: "Name in the specified language" + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" + description: "Language code (ISO 639-1, optionally with ISO 3166-1 country)" + + BaseUnitReference: + type: object + required: ["type", "id", "quantity_reference"] + properties: + type: + type: string + const: "unit" + description: "Reference type indicator" + id: + type: string + description: "Unit identifier" + quantity_reference: + $ref: "#/definitions/QuantityReference" + description: "Physical quantity this base unit measures" + + QuantityReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + const: "quantity" + description: "Reference type indicator" + id: + type: string + description: "Quantity identifier" + + Reference: + type: object + required: ["type"] + properties: + type: + type: string + enum: ["standard", "specification", "publication", "website"] + description: "Type of reference" + authority: + type: string + description: "Authoritative body or organization" + uri: + type: string + format: "uri" + description: "URI to the reference" + title: + type: string + description: "Title of the reference" + year: + type: integer + minimum: 1000 + maximum: 9999 + description: "Publication year" diff --git a/schemas/units-schema.yaml b/schemas/units-schema.yaml new file mode 100644 index 0000000..9a876f6 --- /dev/null +++ b/schemas/units-schema.yaml @@ -0,0 +1,217 @@ +# yaml-language-server: $schema=http://json-schema.org/draft-06/schema +--- +$schema: "http://json-schema.org/draft-06/schema#" +$id: "https://unitsml.org/schemas/units-schema.yaml" +title: "Units Database Schema" +description: "Schema for units.yaml - defines measurement units with their properties, symbols, and relationships" + +type: object +required: ["schema_version", "units"] +properties: + schema_version: + type: string + pattern: "^\\d+\\.\\d+\\.\\d+$" + description: "Semantic version of the schema" + units: + type: array + description: "Array of unit definitions" + items: + $ref: "#/definitions/Unit" + +definitions: + Unit: + type: object + required: ["identifiers", "names", "scale_reference", "unit_system_reference", "root", "short", "symbols"] + properties: + identifiers: + type: array + description: "External identifiers for this unit" + items: + $ref: "#/definitions/Identifier" + names: + type: array + description: "Multilingual names for this unit" + items: + $ref: "#/definitions/Name" + scale_reference: + $ref: "#/definitions/ScaleReference" + description: "Reference to the measurement scale" + unit_system_reference: + type: array + description: "Reference to the unit system" + items: + $ref: "#/definitions/UnitSystemReference" + root: + type: boolean + description: "Whether this unit is a root unit in its system" + root_units: + type: array + description: "Root units that compose this unit" + items: + $ref: "#/definitions/RootUnit" + short: + type: string + description: "Short description or definition" + symbols: + type: array + description: "Mathematical and textual representations" + items: + $ref: "#/definitions/Symbol" + quantity_reference: + $ref: "#/definitions/QuantityReference" + description: "Reference to the physical quantity (optional)" + references: + type: array + description: "External references and citations" + items: + $ref: "#/definitions/Reference" + + Identifier: + type: object + required: ["type", "id"] + properties: + type: + type: string + enum: ["nist", "unitsml", "ucum", "si-digital-framework"] + description: "Type of identifier system" + id: + type: string + description: "Identifier value within the system" + + Name: + type: object + required: ["value", "lang"] + properties: + value: + type: string + description: "Name in the specified language" + lang: + type: string + pattern: "^[a-z]{2}(-[A-Z]{2})?$" + description: "Language code (ISO 639-1, optionally with ISO 3166-1 country)" + + ScaleReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Reference type indicator" + enum: ["unitsml"] + id: + type: string + description: "Scale identifier" + + UnitSystemReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Reference type indicator" + id: + type: string + description: "Unit system identifier" + + QuantityReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Reference type indicator" + enum: ["unitsml", "ucum", "nist"] + id: + type: string + description: "Quantity identifier" + + RootUnit: + type: object + required: ["power", "unit_reference"] + properties: + power: + type: integer + description: "Exponent for this unit in the composition" + unit_reference: + $ref: "#/definitions/UnitReference" + description: "Reference to the base unit" + + UnitReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Reference type indicator" + id: + type: string + description: "Unit identifier" + prefix_reference: + $ref: "#/definitions/PrefixReference" + description: "Optional prefix applied to the unit" + + PrefixReference: + type: object + required: ["type", "id"] + properties: + type: + type: string + description: "Reference type indicator" + id: + type: string + description: "Prefix identifier" + + # - latex: "\\ensuremath{\\mathrm{m}}" + # unicode: m + # ascii: m + # html: m + # id: m + # mathml: "m" + + Symbol: + type: object + required: ["latex", "unicode", "ascii", "html", "id", "mathml"] + description: "Mathematical and textual representations of the unit" + properties: + latex: + type: string + description: "LaTeX representation" + unicode: + type: string + description: "Unicode representation" + ascii: + type: string + description: "ASCII representation" + html: + type: string + description: "HTML representation" + id: + type: string + description: "Symbol identifier" + mathml: + type: string + description: "MathML representation" + + Reference: + type: object + required: ["type"] + properties: + type: + type: string + enum: ["normative", "informative"] + description: "Type of reference" + authority: + type: string + description: "Authoritative body or organization" + uri: + type: string + format: "uri" + description: "URI to the reference" + title: + type: string + description: "Title of the reference" + year: + type: integer + minimum: 1000 + maximum: 9999 + description: "Publication year" diff --git a/unit_systems.yaml b/unit_systems.yaml index 7464e1a..8d2dbc0 100644 --- a/unit_systems.yaml +++ b/unit_systems.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=schemas/unit_systems-schema.yaml --- schema_version: 2.0.0 unit_systems: diff --git a/units.yaml b/units.yaml index 2b38c93..d4908d6 100644 --- a/units.yaml +++ b/units.yaml @@ -1,3 +1,4 @@ +# yaml-language-server: $schema=schemas/units-schema.yaml --- schema_version: 2.0.0 units: diff --git a/validate_schemas.rb b/validate_schemas.rb new file mode 100755 index 0000000..cadf732 --- /dev/null +++ b/validate_schemas.rb @@ -0,0 +1,208 @@ +#!/usr/bin/env ruby + +require 'yaml' +require 'json-schema' +require 'json' +require 'pathname' + +class SchemaValidator + def initialize + @schemas_dir = Pathname.new('schemas') + @errors_found = false + end + + def validate_all + puts "UnitsDB Schema Validation" + puts "=" * 50 + + # Define the mapping of YAML files to their schemas + file_schema_map = { + 'units.yaml' => 'units-schema.yaml', + 'quantities.yaml' => 'quantities-schema.yaml', + 'scales.yaml' => 'scales-schema.yaml', + 'prefixes.yaml' => 'prefixes-schema.yaml', + 'unit_systems.yaml' => 'unit_systems-schema.yaml', + 'dimensions.yaml' => 'dimensions-schema.yaml' + } + + file_schema_map.each do |yaml_file, schema_file| + validate_file(yaml_file, schema_file) + end + + puts "\n" + "=" * 50 + if @errors_found + puts "❌ Validation completed with errors" + exit 1 + else + puts "✅ All files passed validation" + exit 0 + end + end + + private + + def validate_file(yaml_file, schema_file) + puts "\nValidating #{yaml_file}..." + + # Check if files exist + unless File.exist?(yaml_file) + puts "❌ YAML file not found: #{yaml_file}" + @errors_found = true + return + end + + schema_path = @schemas_dir / schema_file + unless File.exist?(schema_path) + puts "❌ Schema file not found: #{schema_path}" + @errors_found = true + return + end + + begin + # Load YAML data + yaml_data = YAML.load_file(yaml_file) + + # Load schema (YAML schemas need to be converted to JSON for json-schema gem) + schema_yaml = YAML.load_file(schema_path) + schema_json = JSON.parse(schema_yaml.to_json) + + # Validate + errors = JSON::Validator.fully_validate(schema_json, yaml_data, + errors_as_objects: true, + validate_schema: true) + + if errors.empty? + puts "✅ #{yaml_file} - Valid" + else + puts "❌ #{yaml_file} - #{errors.length} error(s) found:" + @errors_found = true + + errors.each_with_index do |error, index| + puts "\n Error #{index + 1}:" + puts " Path: #{error[:fragment] || 'root'}" + puts " Message: #{error[:message]}" + + # Try to provide more context about the location + if error[:fragment] && !error[:fragment].empty? + path_parts = error[:fragment].split('/') + puts " Location: #{describe_path(path_parts, yaml_data)}" + end + + # Show the failing value if available + if error[:failed_attribute] && error[:failed_attribute] != 'schema' + puts " Failed validation: #{error[:failed_attribute]}" + end + end + end + + rescue YAML::SyntaxError => e + puts "❌ YAML syntax error in #{yaml_file}:" + puts " Line #{e.line}: #{e.problem}" + @errors_found = true + rescue JSON::Schema::ValidationError => e + puts "❌ Schema validation error: #{e.message}" + @errors_found = true + rescue StandardError => e + puts "❌ Unexpected error validating #{yaml_file}: #{e.message}" + puts " #{e.class}: #{e.backtrace.first}" + @errors_found = true + end + end + + def describe_path(path_parts, data) + current = data + description_parts = [] + + path_parts.each do |part| + next if part.empty? || part == '#' + + if part =~ /^\d+$/ + # Array index + index = part.to_i + if current.is_a?(Array) && current[index] + description_parts << "item #{index}" + current = current[index] + else + description_parts << "index #{index} (out of bounds)" + break + end + else + # Object property + if current.is_a?(Hash) && current.key?(part) + description_parts << "property '#{part}'" + current = current[part] + else + description_parts << "missing property '#{part}'" + break + end + end + end + + description_parts.join(' -> ') + end +end + +# Additional helper methods for detailed error reporting +class SchemaValidator + def self.check_dependencies + begin + require 'json-schema' + rescue LoadError + puts "❌ Missing required gem: json-schema" + puts " Install with: gem install json-schema" + exit 1 + end + end + + def self.run_with_options + check_dependencies + + if ARGV.include?('--help') || ARGV.include?('-h') + show_help + exit 0 + end + + validator = new + + if ARGV.include?('--verbose') || ARGV.include?('-v') + puts "Ruby version: #{RUBY_VERSION}" + puts "JSON Schema gem version: #{JSON::Schema::VERSION}" + puts "Working directory: #{Dir.pwd}" + puts "" + end + + validator.validate_all + end + + def self.show_help + puts <<~HELP + UnitsDB Schema Validator + + Usage: ruby validate_schemas.rb [options] + + Options: + -h, --help Show this help message + -v, --verbose Show additional information + + This script validates all YAML files in the UnitsDB repository + against their corresponding JSON schemas in the schemas/ directory. + + Files validated: + - units.yaml + - quantities.yaml + - scales.yaml + - prefixes.yaml + - unit_systems.yaml + - dimensions.yaml + + Exit codes: + 0 - All files passed validation + 1 - Validation errors found or script error + HELP + end +end + +# Run the validator if this script is executed directly +if __FILE__ == $0 + SchemaValidator.run_with_options +end From 47a09aa1e771ed33f4f608ae10106c3b32a429bd Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Sat, 12 Jul 2025 01:02:01 +0800 Subject: [PATCH 3/4] fix: lint job --- .github/workflows/lint-yaml.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/lint-yaml.yaml b/.github/workflows/lint-yaml.yaml index 0ebbeaa..b9cc415 100644 --- a/.github/workflows/lint-yaml.yaml +++ b/.github/workflows/lint-yaml.yaml @@ -18,17 +18,14 @@ jobs: with: ruby-version: '3.3' bundler-cache: true - working-directory: ./scripts - name: Check YAML normalization id: check_yaml - working-directory: ./scripts run: | bundle exec unitsdb-utils normalize --all --dir .. - name: Check field uniqueness id: check_uniqueness - working-directory: ./scripts run: | bundle exec unitsdb-utils check_uniqueness --all --dir .. From 6b6b3fd274eca82714de2a08c6d634dee9b4e601 Mon Sep 17 00:00:00 2001 From: Ronald Tse Date: Sat, 12 Jul 2025 01:04:33 +0800 Subject: [PATCH 4/4] fix: schema --- schemas/units-schema.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/schemas/units-schema.yaml b/schemas/units-schema.yaml index 9a876f6..5c017b1 100644 --- a/schemas/units-schema.yaml +++ b/schemas/units-schema.yaml @@ -41,6 +41,7 @@ definitions: description: "Reference to the unit system" items: $ref: "#/definitions/UnitSystemReference" + minimum: 1 root: type: boolean description: "Whether this unit is a root unit in its system" @@ -109,6 +110,7 @@ definitions: type: type: string description: "Reference type indicator" + enum: ["unitsml", "ucum", "nist"] id: type: string description: "Unit system identifier"