ts_schema 0.1.11 → 0.1.14

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: 55a01d015705b45bc3b21d80c74fde717172daf0b9cc8f8856ee24bdb6ffe00d
4
- data.tar.gz: 662b58cf50169869845249b218ad760d7f3e4d96b5e833ae916a77a86e8447dd
3
+ metadata.gz: e970a98bd2aea544c74c48dac67799e5b713ef56ab8eaa023662f2901973983a
4
+ data.tar.gz: f259f07ed9fd61a06bf8b0c777df0a50696472534ba48f43737351a8982b3fb5
5
5
  SHA512:
6
- metadata.gz: 5f7ceb576b082e209567755d34c7ce25f826ec61891e3f61662f06289838b087c2d18b61f8fdcbabe4db097f59af90332ac55b861b25242a0cc20bc809ad8e9d
7
- data.tar.gz: 785331c128754a645c9570146244fc01992329ea7864dc40b3295a587f67ce07bacfff3320a6e9a673552eff4f5489c891028715d7675be5965275a5598eb43b
6
+ metadata.gz: 30fcd65e0da2df3d5741fe12ed25f84139d3d94b1bc840661a9404105fe5a15e5a0f7a328817283c23592de13ab196d1d31df4398281c6a186d3afcef0d23eb4
7
+ data.tar.gz: 1a44cc70e7acfb79209f03d2311eb368c1d128832c4e8f586c5ca7f7fa209d5f80641fd8ee57848f6e7b7f9573b1c97e399d372fcb8407b772dd4096b5d1be57
data/README.md CHANGED
@@ -16,9 +16,9 @@ rails generate ts_schema:install
16
16
 
17
17
  ## Usage
18
18
 
19
- All options with their defaults are in the config file.
19
+ All options with their defaults are in the generated initializer file.
20
20
 
21
- By default, every migration, rollback, reset or setup task will auto generate a new schema file, replacing the existing one. You can disable this behavior in the config file.
21
+ By default, every migration will auto generate a new schema file, replacing the existing one. You can disable this behavior in the config file.
22
22
 
23
23
  You can manually generate the schema file by running:
24
24
 
@@ -26,9 +26,51 @@ You can manually generate the schema file by running:
26
26
  rails ts_schema:generate
27
27
  ```
28
28
 
29
+ ### Default type mappings
30
+
31
+ |Ruby Type|Typescript Type|
32
+ |:---|:---|
33
+ |string|string|
34
+ |text|string|
35
+ |integer|number|
36
+ |enum|number|
37
+ |bigint|number|
38
+ |float|number|
39
+ |decimal|number|
40
+ |json|Record<string, any>|
41
+ |jsonb|Record<string, any>|
42
+ |binary|string|
43
+ |boolean|boolean|
44
+ |date|string|
45
+ |datetime|string|
46
+ |timestamp|string|
47
+ |datetime_with_timezone|string|
48
+ |inet|string|
49
+ |cidr|string|
50
+ |macaddr|string|
51
+
52
+ ### Initializer options
53
+
54
+ |Option|Default|Values|Description|
55
+ |---|---|---|---|
56
+ |case |`:camel`|`:camel`<br/>`:snake`<br/>`:pascal`|camelCase<br/>snake_case<br/>PascalCase|
57
+ |output |`Rails.root.join('app', 'assets', 'javascripts', 'schema.d.ts')`|Any path|Path to output generated file|
58
+ |auto_generate |`true`|`boolean`|Whether to automatically (re)generate the defenitions after running migrations|
59
+ |custom_types |`{}`|`{ ruby_type: 'typescriptType' }`|Use to add or override type mappings for any type|
60
+ |default_type |`:string`|Any typescript type|The default output type to use if a ruby type is not included in the type mappings|
61
+ |include_associated|`true`|`boolean`|Whether to include associated models as fields on the generated interfaces|
62
+ |parent_classes |`["ApplicationRecord"]`|Array of string names of top level classes|Any class names included in this array will be querried for subclasses to generate types for|
63
+ |additional_models |`[]`|Array of string names of ActiveRecord models|Add model names which don't inherit from classes included in `parent_classes`, but which should have types generated|
64
+ |field_overrides |`{ encrypted_password: :password, password: :optional, }`|Hash of field names with the following values:<br/> `:optional`: Makes it an optional field by adding '?' to the defintion (example: password?: string)<br/>`:omit`: Omits the field from being output in the schema entirely<br/>`[string]`: Field name override. Will replace any instance of the hash key with the value. The default values replace `password` with `encrypted_password`|Overwrite, omit, or make optional any field name. Applies to all generated classes|
65
+ |namespace |`:schema`|string\|symbol|The typescript namespace to contain generated types|
66
+ |schema_type |`:interface`|`:interface`\|`:type`|Whether to generate typescript definitions as types or interfaces. Interfaces are recommended since they are easier to extend|
67
+ |indent|`:tab`|`:tab`\|`:space`|Indentation using tabs or spaces|
68
+ |spaces|`2`|number|Number of spaces for indentation if indentation is set to spaces|
69
+
70
+
29
71
  ## Gotchas
30
72
 
31
- Apparantly, sometimes ActiveRecord's inflections will alter the class name. For instance, with a class named `Five`; `"Fives".singularize` returns "Fife", which is not the classname. In the case where Rails alters the classname for an association, you must explicitly define it on the association in the model using `class_name`. Example: `has_many :fives, class_name: "Five"`.
73
+ Sometimes ActiveRecord's inflections will alter the class name. For instance, with a class named `Five`; `"Fives".singularize` returns "Fife", which is not the classname. In the case where Rails alters the classname for an association, you must explicitly define it on the association in the model using `class_name`. Example: `has_many :fives, class_name: "Five"`.
32
74
 
33
75
  ## License
34
76
 
@@ -1,57 +1,102 @@
1
1
  TsSchema.setup do |config|
2
- # Options: camel|snake|pascal
2
+ # Case options for field names: camel|snake|pascal
3
+ #
3
4
  # config.case = :camel
4
5
 
6
+
5
7
  # Customize output path and file name
8
+ #
6
9
  # config.output = Rails.root.join('app', 'assets', 'javascripts', 'schema.d.ts')
7
10
 
8
- # Whether to generate the schema file on migrations and rollbacks
11
+
12
+ # Whether to generate the schema file after running migrations
13
+ #
9
14
  # config.auto_generate = true
10
15
 
11
- # Add custom type mappings or overrides
12
- #
13
- # Default type mappings:
14
- #
15
- # string: string
16
- # text: string
17
- # integer: number
18
- # enum: number
19
- # bigint: number
20
- # float: number
21
- # decimal: number
22
- # json: Record<string, any>
23
- # jsonb: Record<string, any>
24
- # binary: string
25
- # boolean: boolean
26
- # date: string
27
- # datetime: string
28
- # timestamp: string
29
- # datetime_with_timezone: string
30
- # inet: string
31
- # cidr: string
32
- # macaddr: string
33
- #
16
+
17
+ # Add custom type mappings or overrides (as strings or symbols)
18
+ #
19
+ # Default type mappings:
20
+ # string: string
21
+ # text: string
22
+ # integer: number
23
+ # enum: number
24
+ # bigint: number
25
+ # float: number
26
+ # decimal: number
27
+ # json: Record<string, any>
28
+ # jsonb: Record<string, any>
29
+ # binary: string
30
+ # boolean: boolean
31
+ # date: string
32
+ # datetime: string
33
+ # timestamp: string
34
+ # datetime_with_timezone: string
35
+ # inet: string
36
+ # cidr: string
37
+ # macaddr: string
38
+ #
34
39
  # config.custom_types = {
35
40
  #
36
41
  # }
37
42
 
43
+
38
44
  # Default type for unrecognized types
45
+ #
39
46
  # config.default_type = :string
40
47
 
41
- # Whether to generate types for associations
48
+
49
+ # Whether to generate types for associated models
50
+ #
42
51
  # config.include_associated = true
43
52
 
44
- # Additional models to map which don't have a model file
45
- # config.additional_models = [
46
- #
47
- # ]
48
53
 
49
- # Namespace
54
+ # Parent classes of models to generate (as strings or symbols)
55
+ # Only classes inheriting from those in this list will have types generated
56
+ #
57
+ # config.parent_classes = [
58
+ # "ApplicationRecord",
59
+ # ]
60
+
61
+
62
+ # Additional models to generate schema from, such as those added by other gems
63
+ # which don't have a model file. (as strings or symbols)
64
+ #
65
+ # config.additional_models = [
66
+ #
67
+ # ]
68
+
69
+
70
+ # Ignore certain fields, omitting them from the generated schema: :optional|(string)|false
71
+ # Key is the name of the field to override options for.
72
+ #
73
+ # [:optional] will make this an optional field by adding '?' to the defintion (example: password?: string)
74
+ # [(string)] enter a field name override, for instance rename encrypted_password to password
75
+ # In that scenario, also specifying password as an optional field will append a ? to password
76
+ # [:omit] will omit the field from being output in the schema entirely
77
+ #
78
+ # config.field_overrides: {
79
+ # encrypted_password: :password,
80
+ # password: :optional,
81
+ # }
82
+
83
+
84
+ # Namespace for generated types
85
+ #
50
86
  # config.namespace = :schema
51
87
 
52
- # Options: tab|space
88
+
89
+ # Output schema as types or interfaces: type|interface
90
+ #
91
+ # config.schema_type = :interface
92
+
93
+
94
+ # Indentation options: tab|space
95
+ #
53
96
  # config.indent = :tab
54
97
 
98
+
55
99
  # If indent is spaces, specify how many
100
+ #
56
101
  # config.spaces = 2
57
102
  end
@@ -10,10 +10,16 @@ module TsSchema
10
10
  custom_types: {},
11
11
  default_type: :string,
12
12
  include_associated: true,
13
+ parent_classes: ["ApplicationRecord"],
14
+ additional_models: [],
15
+ field_overrides: {
16
+ "encrypted_password" => :password,
17
+ "password" => :optional,
18
+ },
13
19
  namespace: :schema,
20
+ schema_type: :interface,
14
21
  indent: :tab,
15
22
  spaces: 2,
16
- additional_models: []
17
23
  }
18
24
 
19
25
  attr_accessor(*DEFAULTS.keys)
@@ -7,15 +7,20 @@ module TsSchema
7
7
 
8
8
  def initialize(config = nil)
9
9
  @config = config || TsSchema::Configuration.new
10
+ @config.field_overrides = @config.field_overrides.stringify_keys
11
+ @models = []
10
12
 
11
13
  Rails.application.eager_load!
12
- # @models = ApplicationRecord.send(:subclasses)
13
- @models = get_subclasses(ApplicationRecord)
14
+ @config.parent_classes.each do |parent|
15
+ @models.concat(get_subclasses(parent.to_s.constantize))
16
+ end
14
17
  unless @config.additional_models.empty?
15
18
  @models.concat(@config.additional_models.map do |m|
16
19
  m.to_s.constantize
17
20
  end)
18
21
  end
22
+ @models.sort_by! { |c| c.name }
23
+
19
24
  @types = @config.types.stringify_keys.merge(@config.custom_types.stringify_keys || {})
20
25
  end
21
26
 
@@ -30,33 +35,19 @@ module TsSchema
30
35
  end
31
36
 
32
37
  def generate
33
- generate_typescript
34
- end
35
-
36
- def output_file
37
- path = @config.output
38
- FileUtils.mkdir_p(File.dirname(path))
39
-
40
- content = generate
41
- return if File.exist?(path) && File.read(path) == content
42
-
43
- File.open(path, 'w') do |f|
44
- f.write content
45
- end
46
- end
47
-
48
- def generate_typescript
49
38
  type_template = ""
39
+
50
40
  @models.each do |model|
51
41
  columns = map_column_types(model)
52
42
  columns.concat(map_associations(model)) if @config.include_associated
53
43
 
54
44
  type_template += <<~TYPESCRIPT
55
- interface #{model.model_name.param_key.camelize} {
45
+ #{@config.schema_type} #{model.model_name.param_key.camelize} #{@config.schema_type.to_sym == :type ? "= " : ""}{
56
46
  #{columns.map { |column| "#{indent_as_str}#{column_name_cased(column[:name])}: #{column[:ts_type]};" }.join("\n")}
57
47
  }\n
58
48
  TYPESCRIPT
59
49
  end
50
+
60
51
  type_template = <<~TPL
61
52
  declare namespace #{@config.namespace} {
62
53
  #{indent_wrapper(type_template)}
@@ -64,19 +55,48 @@ module TsSchema
64
55
  TPL
65
56
  end
66
57
 
58
+ def output_file
59
+ path = @config.output
60
+ FileUtils.mkdir_p(File.dirname(path))
61
+
62
+ content = generate
63
+ return if File.exist?(path) && File.read(path) == content
64
+
65
+ File.open(path, 'w') do |f|
66
+ f.write content
67
+ end
68
+ end
69
+
67
70
  def map_column_types(model)
68
71
  model.columns.map { |i|
72
+ next if @config.field_overrides[i.name.to_s] == :omit
73
+
69
74
  type = @types[i.type.to_s] || @config.default_type
75
+ name = map_name(i.name)
76
+ null = i.null
77
+ null = true if @config.field_overrides[name]&.to_s == "optional"
70
78
 
71
- if(enum = model.defined_enums[i.name])
72
- type = enum.keys.map { |k| "'#{k}'" }.join(" | ")
79
+ if(enum = model.defined_enums[name])
80
+ type = enum.keys.map { |k| "'#{k}'" }.join("|")
73
81
  end
74
-
82
+
75
83
  {
76
- name: "#{i.name}#{"?" if i.null }",
77
- ts_type: "#{type}#{" | null" if i.null}"
84
+ name: "#{name}#{"?" if null }",
85
+ ts_type: "#{type}#{" | null" if null}"
78
86
  }
79
- }
87
+ }.compact
88
+ end
89
+
90
+ def map_name(name)
91
+ final_name = name.to_s
92
+ return final_name unless @config.field_overrides[final_name]
93
+
94
+ if @config.field_overrides[final_name]&.to_s != "optional"
95
+ final_name = @config.field_overrides[final_name]&.to_s
96
+
97
+ final_name = map_name(final_name) if @config.field_overrides[final_name]
98
+ end
99
+ final_name
80
100
  end
81
101
 
82
102
  def map_associations(model)
@@ -1,3 +1,3 @@
1
1
  module TsSchema
2
- VERSION = "0.1.11"
2
+ VERSION = "0.1.14"
3
3
  end
data/lib/ts_schema.rb CHANGED
@@ -34,4 +34,3 @@ module TsSchema
34
34
  end
35
35
 
36
36
  require "generators/install_generator"
37
- require "generators/generate_generator"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ts_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.11
4
+ version: 0.1.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Avram Walden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-06 00:00:00.000000000 Z
11
+ date: 2022-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -48,7 +48,6 @@ files:
48
48
  - MIT-LICENSE
49
49
  - README.md
50
50
  - Rakefile
51
- - lib/generators/generate_generator.rb
52
51
  - lib/generators/install_generator.rb
53
52
  - lib/generators/templates/ts_schema.rb
54
53
  - lib/tasks/ts_schema_tasks.rake
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/generators'
4
- require 'rails/generators/base'
5
-
6
- module TsSchema
7
- module Generators
8
- class GenerateGenerator < Rails::Generators::Base
9
-
10
- desc "Generates a schema.d.ts file"
11
-
12
- def generate_schema
13
- create_file TsSchema.configuration.output, TsSchema.generate
14
- end
15
- end
16
- end
17
- end