blueprinter_schema 1.1.0 → 1.3.0

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: 79f76768380ae6cbe77da6ec153325e079ca2d5ee30df459378e0ebb90f674c2
4
- data.tar.gz: 50a119f7dd0fb32789a24ed6ccddd05026a0bb8525f4c5c60f94f232edcc3e31
3
+ metadata.gz: 0cafd732029c0e4f3cd09d13dd6809e3e68f599c194a24247774e7d18f6233ca
4
+ data.tar.gz: 1bf4791a3812e9f16bd3c8d7f8ed0bc2a91095130b91286fa75d3b72954b1482
5
5
  SHA512:
6
- metadata.gz: f057fdac75f35be16f955cbc083326ab32940ed5210ec8ed26922b4614741e0371e0e762371081d7afdf31dbee97d7fc14794650bde811ef636f3de64a2cb52f
7
- data.tar.gz: e82e0011242c7838709c55c2d4d6ca8d2a43e620a6ff7c244c9fc70b816e6dd7c211a995ebea6fd57390744c0523d2b467168e9fc52e8bdec02ecebb10888811
6
+ metadata.gz: 02577f5a4da542def621be3544ff1c82d4509addfc2b8b7a1264a9a6e7d079943ae75c0574f160354f48ebf3c6b1481eeb09d899a35fb3ed83b169e25671a482
7
+ data.tar.gz: 6690022f62b1a2ad817a362ae2322300e0013c22494b1bb2efe195478c0a6036063c3c31ae422ab92b1745591cacdf4d6aba0356e386df32d1419f28c8ecb717
data/AGENTS.md ADDED
@@ -0,0 +1,23 @@
1
+ # BlueprinterSchema
2
+
3
+ A gem to create JSON Schemas from [Blueprinter](https://github.com/procore-oss/blueprinter) Serializers.
4
+
5
+ ## Instructions
6
+
7
+ - Specs MUST assert the full expected schema, so that they serve as clear documentation of what is generated
8
+
9
+ ## Development Commands
10
+
11
+ ### Setup
12
+
13
+ ```sh
14
+ mise install
15
+ bin/setup
16
+ ```
17
+
18
+ ### Test, lint
19
+
20
+ ```sh
21
+ bundle exec rspec
22
+ bundle exec rubocop -A
23
+ ```
data/README.md CHANGED
@@ -18,6 +18,8 @@ class UserSerializer < Blueprinter::Base
18
18
  field :last_name, type: [:string, :null]
19
19
  field :full_name, type: [:string, :null], description: "The concatendated first and last name."
20
20
  field :email, type: :string, format: :email
21
+ field :role, type: :string, enum: ["user", "admin"]
22
+ field :tags, type: :array, items: { type: :string }
21
23
  end
22
24
 
23
25
  BlueprinterSchema.generate(serializer: UserSerializer)
@@ -40,9 +42,17 @@ BlueprinterSchema.generate(serializer: UserSerializer)
40
42
  "email" => {
41
43
  "type" => "string",
42
44
  "format" => "email"
45
+ },
46
+ "role" => {
47
+ "type" => "string",
48
+ "enum" => ["user", "admin"]
49
+ },
50
+ "tags" => {
51
+ "type" => "array",
52
+ "items" => { "type" => "string" }
43
53
  }
44
54
  },
45
- "required" => ["first_name", "last_name", "full_name", "email"],
55
+ "required" => ["first_name", "last_name", "full_name", "email", "role", "tags"],
46
56
  "additionalProperties" => false
47
57
  }
48
58
  ```
@@ -90,6 +100,7 @@ class UserSerializer < Blueprinter::Base
90
100
 
91
101
  association :addresses, blueprint: AddressSerializer, collection: true
92
102
  association :profile, blueprint: ProfileSerializer
103
+ association :account, blueprint: AccountSerializer, optional: true
93
104
  end
94
105
 
95
106
  class AddressSerializer < Blueprinter::Base
@@ -100,6 +111,10 @@ class ProfileSerializer < Blueprinter::Base
100
111
  field :public, type: :boolean
101
112
  end
102
113
 
114
+ class AccountSerializer < Blueprinter::Base
115
+ field :name, type: :string
116
+ end
117
+
103
118
  BlueprinterSchema.generate(serializer: UserSerializer)
104
119
  ```
105
120
 
@@ -132,6 +147,16 @@ BlueprinterSchema.generate(serializer: UserSerializer)
132
147
  },
133
148
  "required" => ["public"],
134
149
  "additionalProperties" => false
150
+ },
151
+ "account" => {
152
+ "type" => ["object", "null"],
153
+ "properties" => {
154
+ "name" => {
155
+ "type" => "string"
156
+ }
157
+ },
158
+ "required" => ["name"],
159
+ "additionalProperties" => false
135
160
  }
136
161
  },
137
162
  "required" => ["email", "addresses", "profile"],
@@ -146,8 +171,9 @@ BlueprinterSchema.generate(
146
171
  serializer:,
147
172
  model: nil,
148
173
  include_conditional_fields: true, # Whether or not to include conditional fields from the serializer
149
- fallback_type: {}, # Type when no DB column or type definition is found. E.g. { 'type' => 'object' }
150
- view: :default # The blueprint view to use
174
+ fallback_definition: {}, # Type when no DB column or type definition is found. E.g. { 'type' => 'object' }
175
+ view: :default, # The blueprint view to use
176
+ type: "object" # Root type
151
177
  )
152
178
  ```
153
179
 
@@ -5,17 +5,18 @@ module BlueprinterSchema
5
5
 
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class Generator
8
- def initialize(serializer:, model:, skip_conditional_fields:, fallback_definition:, view:)
8
+ def initialize(serializer:, model:, skip_conditional_fields:, fallback_definition:, view:, type:) # rubocop:disable Metrics/ParameterLists
9
9
  @serializer = serializer
10
10
  @model = model
11
11
  @skip_conditional_fields = skip_conditional_fields
12
12
  @fallback_definition = fallback_definition
13
13
  @view = view
14
+ @type = type
14
15
  end
15
16
 
16
17
  def generate
17
18
  schema = {
18
- 'type' => 'object',
19
+ 'type' => @type,
19
20
  'properties' => build_properties,
20
21
  'required' => build_required_fields,
21
22
  'additionalProperties' => false
@@ -63,7 +64,6 @@ module BlueprinterSchema
63
64
  .keys.map(&:to_s)
64
65
  end
65
66
 
66
- # rubocop:disable Metrics/AbcSize
67
67
  def field_to_json_schema(field)
68
68
  type_definition = @fallback_definition.dup
69
69
 
@@ -74,12 +74,16 @@ module BlueprinterSchema
74
74
  type_definition = ar_column_to_json_schema(column)
75
75
  end
76
76
 
77
- type_definition['items'] = field.options[:items].deep_stringify_keys if field.options[:items]
78
- type_definition['format'] = field.options[:format] if field.options[:format]
79
- type_definition['description'] = field.options[:description] if field.options[:description]
77
+ merge_field_options(type_definition, field.options)
78
+ end
79
+
80
+ def merge_field_options(type_definition, options)
81
+ type_definition['enum'] = options[:enum] if options[:enum]
82
+ type_definition['items'] = options[:items].deep_stringify_keys if options[:items]
83
+ type_definition['format'] = options[:format] if options[:format]
84
+ type_definition['description'] = options[:description] if options[:description]
80
85
  type_definition
81
86
  end
82
- # rubocop:enable Metrics/AbcSize
83
87
 
84
88
  def ensure_valid_json_schema_types!(field)
85
89
  types = [field.options[:type]].flatten.map(&:to_s)
@@ -120,7 +124,7 @@ module BlueprinterSchema
120
124
  type
121
125
  end
122
126
 
123
- def association_to_json_schema(association)
127
+ def association_to_json_schema(association) # rubocop:disable Metrics/CyclomaticComplexity
124
128
  blueprint_class = association.options[:blueprint]
125
129
 
126
130
  return { 'type' => 'object' } unless blueprint_class
@@ -129,18 +133,20 @@ module BlueprinterSchema
129
133
  is_collection = ar_association ? ar_association.collection? : association.options[:collection]
130
134
 
131
135
  view = association.options[:view] || :default
132
- associated_schema = recursive_generate(blueprint_class, ar_association&.klass, view)
136
+ type = association.options[:optional] ? %w[object null] : 'object'
137
+ associated_schema = recursive_generate(blueprint_class, ar_association&.klass, view, type:)
133
138
 
134
139
  is_collection ? { 'type' => 'array', 'items' => associated_schema } : associated_schema
135
140
  end
136
141
 
137
- def recursive_generate(serializer, model, view)
142
+ def recursive_generate(serializer, model, view, type:)
138
143
  BlueprinterSchema.generate(
139
144
  serializer:,
140
145
  model:,
141
146
  skip_conditional_fields: @skip_conditional_fields,
142
147
  fallback_definition: @fallback_definition,
143
- view:
148
+ view:,
149
+ type:
144
150
  )
145
151
  end
146
152
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BlueprinterSchema
4
- VERSION = '1.1.0'
4
+ VERSION = '1.3.0'
5
5
  end
@@ -4,13 +4,14 @@ require_relative 'blueprinter_schema/version'
4
4
  require_relative 'blueprinter_schema/generator'
5
5
 
6
6
  module BlueprinterSchema
7
- def self.generate(
7
+ def self.generate( # rubocop:disable Metrics/ParameterLists
8
8
  serializer:,
9
9
  model: nil,
10
10
  skip_conditional_fields: false,
11
11
  fallback_definition: {},
12
- view: :default
12
+ view: :default,
13
+ type: 'object'
13
14
  )
14
- Generator.new(serializer:, model:, skip_conditional_fields:, fallback_definition:, view:).generate
15
+ Generator.new(serializer:, model:, skip_conditional_fields:, fallback_definition:, view:, type:).generate
15
16
  end
16
17
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blueprinter_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thisismydesign
@@ -19,6 +19,7 @@ files:
19
19
  - ".rspec"
20
20
  - ".rubocop.yml"
21
21
  - ".tool-versions"
22
+ - AGENTS.md
22
23
  - Dockerfile
23
24
  - LICENSE.txt
24
25
  - README.md