lutaml-jsonschema 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31a527e5dd1e038e5c5fc36559c1d9a169581eb57f48ecafd87b55e941202154
4
- data.tar.gz: 39f1bc49c2a3143fd73b156a9e560c83597540d3707906c4e1dd128cbd1f640d
3
+ metadata.gz: d756394e76dba6d56e58308f5b5bf05dee2426f3ed1f06741db6d42e2b9b0722
4
+ data.tar.gz: 1dda2ab2e8d89fc28c62df3a278d4bba0ef3e0bcb21a38176fc3816c4922927d
5
5
  SHA512:
6
- metadata.gz: a0f41867a7d7220534d7e0f4301aa5b624fde7f1a60b6ce152a9ea3fad666e8fe76201de9256b9eb4209eb515927512b39346001a21975177227076953be0616
7
- data.tar.gz: 672ea77bd554cd8a288cdd0b54a7d196efaf141861177af25d9225372b56fe4832caf3773b21b9e6131b72950aff899bdd732ce63847c74a8e9b23af160b18bd
6
+ metadata.gz: 24cc7e89987cd5d49cf5bda35a6a43af05f6de286755d2f324128eca05d643972095eb56d9375406f714ebf11f2b5731563d02f2c8a20f6972fc056ba0727b94
7
+ data.tar.gz: 9d65c1d9e86e2321d561f5853ac2d1617231b267f0ff0d32dbeab6e28f6b4067ecf1fc5fa8458df7db49fbe6dc4fc0e6cf8664abaf5f4a714b7a48cb3ca2442c
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-08 02:21:36 UTC using RuboCop version 1.86.1.
3
+ # on 2026-05-08 02:42:09 UTC using RuboCop version 1.86.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -51,7 +51,7 @@ Lint/IneffectiveAccessModifier:
51
51
  Exclude:
52
52
  - 'lib/lutaml/jsonschema/schema_set.rb'
53
53
 
54
- # Offense count: 14
54
+ # Offense count: 15
55
55
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
56
56
  Metrics/AbcSize:
57
57
  Exclude:
@@ -34,35 +34,35 @@
34
34
  <span class="meta-label">Type</span>
35
35
  <span class="badge badge-type">{{ itemType }}</span>
36
36
  </div>
37
- <div v-if="item.kind === 'property' && (item as any).property.format" class="meta-row">
37
+ <div v-if="propertyItem?.format" class="meta-row">
38
38
  <span class="meta-label">Format</span>
39
- <span class="badge badge-format">{{ (item as any).property.format }}</span>
39
+ <span class="badge badge-format">{{ propertyItem.format }}</span>
40
40
  </div>
41
41
  <div v-if="itemDescription" class="meta-row">
42
42
  <span class="meta-label">Description</span>
43
43
  <span class="text-secondary">{{ itemDescription }}</span>
44
44
  </div>
45
- <div v-if="item.kind === 'property'" class="meta-row">
45
+ <div v-if="propertyItem" class="meta-row">
46
46
  <span class="meta-label">Required</span>
47
- <span :class="['badge', (item as any).property.required ? 'badge-required' : 'badge-optional']">
48
- {{ (item as any).property.required ? 'Yes' : 'No' }}
47
+ <span :class="['badge', propertyItem.required ? 'badge-required' : 'badge-optional']">
48
+ {{ propertyItem.required ? 'Yes' : 'No' }}
49
49
  </span>
50
50
  </div>
51
- <div v-if="item.kind === 'property' && (item as any).property.deprecated" class="meta-row">
51
+ <div v-if="propertyItem?.deprecated" class="meta-row">
52
52
  <span class="meta-label">Status</span>
53
53
  <span class="badge badge-deprecated">Deprecated</span>
54
54
  </div>
55
- <div v-if="item.kind === 'property' && (item as any).property.ref" class="meta-row">
55
+ <div v-if="propertyItem?.ref" class="meta-row">
56
56
  <span class="meta-label">Reference</span>
57
- <span class="font-mono text-secondary">{{ (item as any).property.ref }}</span>
57
+ <span class="font-mono text-secondary">{{ propertyItem.ref }}</span>
58
58
  </div>
59
- <div v-if="item.kind === 'property' && (item as any).property.compositionSource" class="meta-row">
59
+ <div v-if="propertyItem?.compositionSource" class="meta-row">
60
60
  <span class="meta-label">Source</span>
61
- <span class="badge badge-composition-detail">{{ (item as any).property.compositionSource }}</span>
61
+ <span class="badge badge-composition-detail">{{ propertyItem.compositionSource }}</span>
62
62
  </div>
63
- <div v-if="item.kind === 'property' && (item as any).property.default" class="meta-row">
63
+ <div v-if="propertyItem?.default" class="meta-row">
64
64
  <span class="meta-label">Default</span>
65
- <span class="font-mono">{{ (item as any).property.default }}</span>
65
+ <span class="font-mono">{{ propertyItem.default }}</span>
66
66
  </div>
67
67
  <div v-if="item.kind === 'schema' && schema.required.length" class="meta-row">
68
68
  <span class="meta-label">Required</span>
@@ -102,75 +102,75 @@
102
102
  </div>
103
103
 
104
104
  <!-- Constraints for property -->
105
- <div v-if="item.kind === 'property' && hasConstraints" class="detail-section">
105
+ <div v-if="propertyItem && hasConstraints" class="detail-section">
106
106
  <h3 class="detail-heading">Constraints</h3>
107
107
  <table class="table constraint-table">
108
108
  <tbody>
109
- <tr v-if="(item as any).property.minimum != null">
109
+ <tr v-if="propertyItem.minimum != null">
110
110
  <td class="constraint-key">Minimum</td>
111
- <td>{{ (item as any).property.minimum }}</td>
111
+ <td>{{ propertyItem.minimum }}</td>
112
112
  </tr>
113
- <tr v-if="(item as any).property.maximum != null">
113
+ <tr v-if="propertyItem.maximum != null">
114
114
  <td class="constraint-key">Maximum</td>
115
- <td>{{ (item as any).property.maximum }}</td>
115
+ <td>{{ propertyItem.maximum }}</td>
116
116
  </tr>
117
- <tr v-if="(item as any).property.minLength != null">
117
+ <tr v-if="propertyItem.minLength != null">
118
118
  <td class="constraint-key">Min Length</td>
119
- <td>{{ (item as any).property.minLength }}</td>
119
+ <td>{{ propertyItem.minLength }}</td>
120
120
  </tr>
121
- <tr v-if="(item as any).property.maxLength != null">
121
+ <tr v-if="propertyItem.maxLength != null">
122
122
  <td class="constraint-key">Max Length</td>
123
- <td>{{ (item as any).property.maxLength }}</td>
123
+ <td>{{ propertyItem.maxLength }}</td>
124
124
  </tr>
125
- <tr v-if="(item as any).property.pattern">
125
+ <tr v-if="propertyItem.pattern">
126
126
  <td class="constraint-key">Pattern</td>
127
- <td class="font-mono">{{ (item as any).property.pattern }}</td>
127
+ <td class="font-mono">{{ propertyItem.pattern }}</td>
128
128
  </tr>
129
- <tr v-if="(item as any).property.enum?.length">
129
+ <tr v-if="propertyItem.enum?.length">
130
130
  <td class="constraint-key">Enum</td>
131
- <td>{{ (item as any).property.enum.join(', ') }}</td>
131
+ <td>{{ propertyItem.enum.join(', ') }}</td>
132
132
  </tr>
133
- <tr v-if="(item as any).property.itemsType">
133
+ <tr v-if="propertyItem.itemsType">
134
134
  <td class="constraint-key">Items</td>
135
- <td>{{ (item as any).property.itemsType }}</td>
135
+ <td>{{ propertyItem.itemsType }}</td>
136
136
  </tr>
137
- <tr v-if="(item as any).property.exclusiveMinimum != null">
137
+ <tr v-if="propertyItem.exclusiveMinimum != null">
138
138
  <td class="constraint-key">Exclusive Min</td>
139
- <td>{{ (item as any).property.exclusiveMinimum }}</td>
139
+ <td>{{ propertyItem.exclusiveMinimum }}</td>
140
140
  </tr>
141
- <tr v-if="(item as any).property.exclusiveMaximum != null">
141
+ <tr v-if="propertyItem.exclusiveMaximum != null">
142
142
  <td class="constraint-key">Exclusive Max</td>
143
- <td>{{ (item as any).property.exclusiveMaximum }}</td>
143
+ <td>{{ propertyItem.exclusiveMaximum }}</td>
144
144
  </tr>
145
- <tr v-if="(item as any).property.minItems != null">
145
+ <tr v-if="propertyItem.minItems != null">
146
146
  <td class="constraint-key">Min Items</td>
147
- <td>{{ (item as any).property.minItems }}</td>
147
+ <td>{{ propertyItem.minItems }}</td>
148
148
  </tr>
149
- <tr v-if="(item as any).property.maxItems != null">
149
+ <tr v-if="propertyItem.maxItems != null">
150
150
  <td class="constraint-key">Max Items</td>
151
- <td>{{ (item as any).property.maxItems }}</td>
151
+ <td>{{ propertyItem.maxItems }}</td>
152
152
  </tr>
153
- <tr v-if="(item as any).property.uniqueItems">
153
+ <tr v-if="propertyItem.uniqueItems">
154
154
  <td class="constraint-key">Unique Items</td>
155
155
  <td>Yes</td>
156
156
  </tr>
157
- <tr v-if="(item as any).property.multipleOf != null">
157
+ <tr v-if="propertyItem.multipleOf != null">
158
158
  <td class="constraint-key">Multiple Of</td>
159
- <td>{{ (item as any).property.multipleOf }}</td>
159
+ <td>{{ propertyItem.multipleOf }}</td>
160
160
  </tr>
161
- <tr v-if="(item as any).property.const != null">
161
+ <tr v-if="propertyItem.const != null">
162
162
  <td class="constraint-key">Const</td>
163
- <td class="font-mono">{{ (item as any).property.const }}</td>
163
+ <td class="font-mono">{{ propertyItem.const }}</td>
164
164
  </tr>
165
- <tr v-if="(item as any).property.contentMediaType">
165
+ <tr v-if="propertyItem.contentMediaType">
166
166
  <td class="constraint-key">Content Type</td>
167
- <td>{{ (item as any).property.contentMediaType }}</td>
167
+ <td>{{ propertyItem.contentMediaType }}</td>
168
168
  </tr>
169
- <tr v-if="(item as any).property.contentEncoding">
169
+ <tr v-if="propertyItem.contentEncoding">
170
170
  <td class="constraint-key">Content Encoding</td>
171
- <td>{{ (item as any).property.contentEncoding }}</td>
171
+ <td>{{ propertyItem.contentEncoding }}</td>
172
172
  </tr>
173
- <tr v-if="(item as any).property.additionalProperties === false">
173
+ <tr v-if="propertyItem.additionalProperties === false">
174
174
  <td class="constraint-key">Additional Props</td>
175
175
  <td>Denied</td>
176
176
  </tr>
@@ -296,8 +296,8 @@ function formatExample(value: unknown): string {
296
296
  }
297
297
 
298
298
  const hasConstraints = computed(() => {
299
- if (item.value?.kind !== 'property') return false
300
- const p = item.value.property
299
+ const p = propertyItem.value
300
+ if (!p) return false
301
301
  return p.minimum != null || p.maximum != null ||
302
302
  p.minLength != null || p.maxLength != null ||
303
303
  p.pattern || p.enum?.length || p.itemsType ||
@@ -374,6 +374,11 @@ const currentTabs = computed<{ id: TabId; label: string }[]>(() => {
374
374
  }
375
375
  return tabs
376
376
  })
377
+
378
+ const propertyItem = computed<SpaProperty | null>(() => {
379
+ if (item.value?.kind !== 'property') return null
380
+ return item.value.property
381
+ })
377
382
  </script>
378
383
 
379
384
  <style scoped>
@@ -309,7 +309,7 @@ function validate(name: string, rawValue: string, prop: SpaProperty) {
309
309
  validationErrors.value = m
310
310
  }
311
311
 
312
- const fields = ref<BuilderField[]>(props.properties.map(p => createField(p, props.required, props.schema, props.allSchemas)))
312
+ const fields = ref<BuilderField[]>(props.properties.map(p => createField(p, props.required, props.schema, props.allSchemas, depth)))
313
313
 
314
314
  const sortedFields = computed(() => {
315
315
  return [...fields.value].sort((a, b) => {
@@ -801,10 +801,11 @@ async function copyJson() {
801
801
 
802
802
  .constraint-chip {
803
803
  font-size: 11px;
804
- color: var(--text-muted);
805
- background: var(--bg-secondary);
804
+ color: var(--color-primary);
805
+ background: var(--color-primary-alpha);
806
806
  padding: 1px 5px;
807
807
  border-radius: var(--radius-sm);
808
+ border: 1px solid rgba(91, 156, 212, 0.2);
808
809
  }
809
810
 
810
811
  .constraint-chip.chip-pattern {
@@ -838,30 +839,56 @@ async function copyJson() {
838
839
  .constraint-chip.chip-locked {
839
840
  color: var(--color-orange);
840
841
  background: var(--color-orange-alpha);
842
+ border-color: rgba(234, 86, 36, 0.2);
841
843
  font-weight: 500;
842
844
  }
843
845
 
846
+ .constraint-chip.chip-default {
847
+ color: var(--text-secondary);
848
+ background: var(--bg-secondary);
849
+ border-color: var(--border-light);
850
+ }
851
+
852
+ .constraint-chip.chip-const {
853
+ color: var(--color-primary);
854
+ background: var(--color-primary-alpha);
855
+ border-color: rgba(91, 156, 212, 0.2);
856
+ }
857
+
858
+ .constraint-chip.chip-unique {
859
+ color: var(--color-teal);
860
+ background: var(--color-teal-alpha);
861
+ border-color: rgba(96, 195, 167, 0.2);
862
+ }
863
+
844
864
  .constraint-chip.chip-example {
845
865
  font-style: italic;
846
- color: var(--text-muted);
866
+ color: var(--text-secondary);
847
867
  background: transparent;
848
868
  padding: 0;
869
+ border: none;
849
870
  margin-right: 0;
850
871
  }
851
872
 
852
873
  .example-chip {
853
874
  font-size: 10px;
854
875
  font-family: var(--font-mono);
855
- color: var(--color-primary);
856
- background: var(--color-primary-alpha);
876
+ color: var(--text-primary);
877
+ background: rgba(28, 25, 23, 0.04);
857
878
  padding: 1px 5px;
858
879
  border-radius: var(--radius-sm);
880
+ border: 1px solid var(--border-light);
859
881
  max-width: 200px;
860
882
  overflow: hidden;
861
883
  text-overflow: ellipsis;
862
884
  white-space: nowrap;
863
885
  }
864
886
 
887
+ :root[data-theme="dark"] .example-chip {
888
+ background: rgba(255, 255, 255, 0.06);
889
+ border-color: var(--border-medium);
890
+ }
891
+
865
892
  /* Enum chips */
866
893
  .enum-chip {
867
894
  font-size: 10px;
@@ -888,19 +915,29 @@ async function copyJson() {
888
915
  border: 1px solid var(--border-light);
889
916
  border-radius: var(--radius-md);
890
917
  background: var(--bg-secondary);
891
- border-left: 3px solid var(--color-primary);
892
918
  position: relative;
893
919
  }
894
920
 
921
+ /* Tree line connector: vertical line from parent to nested section */
895
922
  .nested-section::before {
896
923
  content: '';
897
924
  position: absolute;
898
925
  left: -11px;
899
926
  top: 0;
900
927
  bottom: 0;
901
- width: 2px;
902
- background: var(--border-light);
903
- border-radius: 1px;
928
+ width: 1px;
929
+ background: var(--border-medium);
930
+ }
931
+
932
+ /* Tree line connector: horizontal branch into nested section */
933
+ .nested-section::after {
934
+ content: '';
935
+ position: absolute;
936
+ left: -11px;
937
+ top: 14px;
938
+ width: 10px;
939
+ height: 1px;
940
+ background: var(--border-medium);
904
941
  }
905
942
 
906
943
  /* Depth-aware alternating backgrounds */
@@ -24,17 +24,19 @@ export function createField(
24
24
  requiredNames: string[],
25
25
  schema: SpaSchema,
26
26
  allSchemas?: SpaSchema[],
27
+ depth: number = 0,
27
28
  ): BuilderField {
28
29
  const isReq = requiredNames.includes(prop.name) || prop.required === true
29
30
  const def = resolveSchemaRef(prop.ref, schema, allSchemas)
30
31
  const isArray = primaryType(prop.type) === 'array'
32
+ const shouldExpand = depth === 0 && !!def && def.properties.length <= 8
31
33
 
32
34
  return {
33
35
  prop,
34
36
  included: isReq,
35
37
  isRequired: isReq,
36
38
  rawValue: initialValue(prop),
37
- expanded: false,
39
+ expanded: shouldExpand,
38
40
  resolvedDef: def,
39
41
  nestedJson: def ? buildDefaultJson(def.properties) : {},
40
42
  arrayItems: isArray ? [arrayDefaultValue(prop.itemsType)] : [],
@@ -52,6 +52,10 @@ export interface SpaDefinition {
52
52
  examples?: string[]
53
53
  minProperties?: number
54
54
  maxProperties?: number
55
+ additionalProperties?: boolean
56
+ hasAllOf?: boolean
57
+ hasAnyOf?: boolean
58
+ hasOneOf?: boolean
55
59
  }
56
60
 
57
61
  export interface SpaSchema {
@@ -89,6 +89,10 @@
89
89
  <span v-if="def.examples?.length" class="text-muted">&middot; {{ def.examples.length }} ex</span>
90
90
  <span v-if="def.minProperties != null" class="text-muted">&middot; min {{ def.minProperties }}</span>
91
91
  <span v-if="def.maxProperties != null" class="text-muted">&middot; max {{ def.maxProperties }}</span>
92
+ <span v-if="def.additionalProperties === false" class="badge badge-locked">no additional</span>
93
+ <span v-if="def.hasAllOf" class="badge badge-composition">allOf</span>
94
+ <span v-if="def.hasAnyOf" class="badge badge-composition">anyOf</span>
95
+ <span v-if="def.hasOneOf" class="badge badge-composition">oneOf</span>
92
96
  </div>
93
97
  <div class="def-card-info">
94
98
  <p v-if="def.description" class="def-card-desc text-secondary" v-html="renderInlineMarkdown(def.description)"></p>
@@ -168,6 +168,10 @@ module Lutaml
168
168
  examples: s.examples,
169
169
  min_properties: s.min_properties,
170
170
  max_properties: s.max_properties,
171
+ additional_properties: s.additional_properties,
172
+ has_all_of: s.all_of.any?,
173
+ has_any_of: s.any_of.any?,
174
+ has_one_of: s.one_of.any?,
171
175
  )
172
176
  end
173
177
  end
@@ -232,6 +236,7 @@ module Lutaml
232
236
  entries = [SpaSearchEntry.new(
233
237
  name: spa_schema.name,
234
238
  title: spa_schema.title,
239
+ description: spa_schema.description,
235
240
  type: "schema",
236
241
  schema_name: spa_schema.name,
237
242
  )]
@@ -240,6 +245,7 @@ module Lutaml
240
245
  entries << SpaSearchEntry.new(
241
246
  name: prop.name,
242
247
  title: prop.title,
248
+ description: prop.description,
243
249
  type: "property",
244
250
  schema_name: spa_schema.name,
245
251
  )
@@ -249,6 +255,7 @@ module Lutaml
249
255
  entries << SpaSearchEntry.new(
250
256
  name: defn.name,
251
257
  title: defn.title,
258
+ description: defn.description,
252
259
  type: "definition",
253
260
  schema_name: spa_schema.name,
254
261
  )
@@ -257,6 +264,7 @@ module Lutaml
257
264
  entries << SpaSearchEntry.new(
258
265
  name: prop.name,
259
266
  title: prop.title,
267
+ description: prop.description,
260
268
  type: "property",
261
269
  schema_name: spa_schema.name,
262
270
  )
@@ -14,6 +14,10 @@ module Lutaml
14
14
  attribute :examples, :string, collection: true
15
15
  attribute :min_properties, :integer
16
16
  attribute :max_properties, :integer
17
+ attribute :additional_properties, :boolean
18
+ attribute :has_all_of, :boolean
19
+ attribute :has_any_of, :boolean
20
+ attribute :has_one_of, :boolean
17
21
 
18
22
  json do
19
23
  map "name", to: :name
@@ -25,6 +29,10 @@ module Lutaml
25
29
  map "examples", to: :examples
26
30
  map "minProperties", to: :min_properties
27
31
  map "maxProperties", to: :max_properties
32
+ map "additionalProperties", to: :additional_properties
33
+ map "hasAllOf", to: :has_all_of
34
+ map "hasAnyOf", to: :has_any_of
35
+ map "hasOneOf", to: :has_one_of
28
36
  end
29
37
  end
30
38
  end
@@ -6,12 +6,14 @@ module Lutaml
6
6
  class SpaSearchEntry < Base
7
7
  attribute :name, :string
8
8
  attribute :title, :string
9
+ attribute :description, :string
9
10
  attribute :type, :string
10
11
  attribute :schema_name, :string
11
12
 
12
13
  json do
13
14
  map "name", to: :name
14
15
  map "title", to: :title
16
+ map "description", to: :description
15
17
  map "type", to: :type
16
18
  map "schemaName", to: :schema_name
17
19
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Jsonschema
5
- VERSION = "0.1.7"
5
+ VERSION = "0.1.9"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-jsonschema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.