api_maker 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +476 -0
  4. data/Rakefile +27 -0
  5. data/app/channels/api_maker/subscriptions_channel.rb +80 -0
  6. data/app/controllers/api_maker/base_controller.rb +32 -0
  7. data/app/controllers/api_maker/commands_controller.rb +26 -0
  8. data/app/controllers/api_maker/devise_controller.rb +60 -0
  9. data/app/controllers/api_maker/session_statuses_controller.rb +33 -0
  10. data/app/services/api_maker/application_service.rb +7 -0
  11. data/app/services/api_maker/collection_command_service.rb +24 -0
  12. data/app/services/api_maker/command_response.rb +67 -0
  13. data/app/services/api_maker/command_service.rb +31 -0
  14. data/app/services/api_maker/create_command.rb +62 -0
  15. data/app/services/api_maker/create_command_service.rb +18 -0
  16. data/app/services/api_maker/destroy_command.rb +39 -0
  17. data/app/services/api_maker/destroy_command_service.rb +22 -0
  18. data/app/services/api_maker/generate_react_native_api_service.rb +61 -0
  19. data/app/services/api_maker/index_command.rb +96 -0
  20. data/app/services/api_maker/index_command_service.rb +22 -0
  21. data/app/services/api_maker/js_method_namer_service.rb +11 -0
  22. data/app/services/api_maker/member_command_service.rb +25 -0
  23. data/app/services/api_maker/model_content_generator_service.rb +108 -0
  24. data/app/services/api_maker/models_finder_service.rb +22 -0
  25. data/app/services/api_maker/models_generator_service.rb +104 -0
  26. data/app/services/api_maker/update_command.rb +43 -0
  27. data/app/services/api_maker/update_command_service.rb +21 -0
  28. data/app/services/api_maker/valid_command.rb +35 -0
  29. data/app/services/api_maker/valid_command_service.rb +21 -0
  30. data/app/views/api_maker/_data.html.erb +15 -0
  31. data/config/rails_best_practices.yml +55 -0
  32. data/config/routes.rb +7 -0
  33. data/lib/api_maker.rb +36 -0
  34. data/lib/api_maker/ability.rb +39 -0
  35. data/lib/api_maker/ability_loader.rb +21 -0
  36. data/lib/api_maker/action_controller_base_extensions.rb +5 -0
  37. data/lib/api_maker/base_command.rb +81 -0
  38. data/lib/api_maker/base_resource.rb +78 -0
  39. data/lib/api_maker/collection_serializer.rb +69 -0
  40. data/lib/api_maker/command_spec_helper.rb +57 -0
  41. data/lib/api_maker/configuration.rb +34 -0
  42. data/lib/api_maker/engine.rb +5 -0
  43. data/lib/api_maker/individual_command.rb +37 -0
  44. data/lib/api_maker/javascript/api.js +92 -0
  45. data/lib/api_maker/javascript/base-model.js +543 -0
  46. data/lib/api_maker/javascript/bootstrap/attribute-row.jsx +16 -0
  47. data/lib/api_maker/javascript/bootstrap/attribute-rows.jsx +47 -0
  48. data/lib/api_maker/javascript/bootstrap/card.jsx +79 -0
  49. data/lib/api_maker/javascript/bootstrap/checkbox.jsx +127 -0
  50. data/lib/api_maker/javascript/bootstrap/checkboxes.jsx +105 -0
  51. data/lib/api_maker/javascript/bootstrap/live-table.jsx +168 -0
  52. data/lib/api_maker/javascript/bootstrap/money-input.jsx +136 -0
  53. data/lib/api_maker/javascript/bootstrap/radio-buttons.jsx +80 -0
  54. data/lib/api_maker/javascript/bootstrap/select.jsx +168 -0
  55. data/lib/api_maker/javascript/bootstrap/string-input.jsx +203 -0
  56. data/lib/api_maker/javascript/cable-connection-pool.js +169 -0
  57. data/lib/api_maker/javascript/cable-subscription-pool.js +111 -0
  58. data/lib/api_maker/javascript/cable-subscription.js +33 -0
  59. data/lib/api_maker/javascript/collection.js +186 -0
  60. data/lib/api_maker/javascript/commands-pool.js +123 -0
  61. data/lib/api_maker/javascript/custom-error.js +14 -0
  62. data/lib/api_maker/javascript/deserializer.js +35 -0
  63. data/lib/api_maker/javascript/devise.js.erb +113 -0
  64. data/lib/api_maker/javascript/error-logger.js +119 -0
  65. data/lib/api_maker/javascript/event-connection.jsx +24 -0
  66. data/lib/api_maker/javascript/event-created.jsx +26 -0
  67. data/lib/api_maker/javascript/event-destroyed.jsx +26 -0
  68. data/lib/api_maker/javascript/event-emitter-listener.jsx +32 -0
  69. data/lib/api_maker/javascript/event-listener.jsx +41 -0
  70. data/lib/api_maker/javascript/event-updated.jsx +26 -0
  71. data/lib/api_maker/javascript/form-data-to-object.js +70 -0
  72. data/lib/api_maker/javascript/included.js +39 -0
  73. data/lib/api_maker/javascript/key-value-store.js +47 -0
  74. data/lib/api_maker/javascript/logger.js +23 -0
  75. data/lib/api_maker/javascript/model-name.js +21 -0
  76. data/lib/api_maker/javascript/model-template.js.erb +110 -0
  77. data/lib/api_maker/javascript/models-response-reader.js +43 -0
  78. data/lib/api_maker/javascript/paginate.jsx +128 -0
  79. data/lib/api_maker/javascript/params.js +68 -0
  80. data/lib/api_maker/javascript/resource-route.jsx +75 -0
  81. data/lib/api_maker/javascript/resource-routes.jsx +36 -0
  82. data/lib/api_maker/javascript/result.js +25 -0
  83. data/lib/api_maker/javascript/session-status-updater.js +113 -0
  84. data/lib/api_maker/javascript/sort-link.jsx +88 -0
  85. data/lib/api_maker/javascript/updated-attribute.jsx +60 -0
  86. data/lib/api_maker/loader.rb +14 -0
  87. data/lib/api_maker/memory_storage.rb +65 -0
  88. data/lib/api_maker/model_extensions.rb +96 -0
  89. data/lib/api_maker/permitted_params_argument.rb +12 -0
  90. data/lib/api_maker/preloader.rb +91 -0
  91. data/lib/api_maker/preloader_belongs_to.rb +58 -0
  92. data/lib/api_maker/preloader_has_many.rb +69 -0
  93. data/lib/api_maker/preloader_has_one.rb +70 -0
  94. data/lib/api_maker/preloader_through.rb +101 -0
  95. data/lib/api_maker/railtie.rb +14 -0
  96. data/lib/api_maker/relationship_includer.rb +42 -0
  97. data/lib/api_maker/resource_routing.rb +8 -0
  98. data/lib/api_maker/result_parser.rb +50 -0
  99. data/lib/api_maker/serializer.rb +86 -0
  100. data/lib/api_maker/spec_helper.rb +100 -0
  101. data/lib/api_maker/version.rb +3 -0
  102. data/lib/tasks/api_maker_tasks.rake +5 -0
  103. metadata +581 -0
@@ -0,0 +1,18 @@
1
+ class ApiMaker::CreateCommandService < ApiMaker::CommandService
2
+ def execute
3
+ ApiMaker::CreateCommand.execute_in_thread!(
4
+ ability: ability,
5
+ args: args,
6
+ collection: collection,
7
+ commands: commands,
8
+ command_response: command_response,
9
+ controller: controller
10
+ )
11
+
12
+ ServicePattern::Response.new(success: true)
13
+ end
14
+
15
+ def collection
16
+ @collection ||= model_class.accessible_by(@ability, :create)
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ class ApiMaker::DestroyCommand < ApiMaker::BaseCommand
2
+ attr_reader :command, :model, :params, :serializer
3
+
4
+ def execute!
5
+ each_command do |command|
6
+ @command = command
7
+ @model = command.model
8
+ @params = command.args || {}
9
+ @serializer = serialized_resource(model)
10
+
11
+ if command.model.destroy
12
+ success_response
13
+ else
14
+ failure_response
15
+ end
16
+ end
17
+
18
+ ServicePattern::Response.new(success: true)
19
+ end
20
+
21
+ def failure_response
22
+ command.fail(
23
+ model: serializer.result,
24
+ success: false,
25
+ errors: model.errors.full_messages
26
+ )
27
+ end
28
+
29
+ def serialized_resource(model)
30
+ ApiMaker::Serializer.new(ability: current_ability, args: api_maker_args, model: model)
31
+ end
32
+
33
+ def success_response
34
+ command.result(
35
+ model: serializer.result,
36
+ success: true
37
+ )
38
+ end
39
+ end
@@ -0,0 +1,22 @@
1
+ class ApiMaker::DestroyCommandService < ApiMaker::CommandService
2
+ def execute
3
+ ApiMaker::DestroyCommand.execute_in_thread!(
4
+ ability: ability,
5
+ args: args,
6
+ collection: collection,
7
+ commands: commands,
8
+ command_response: command_response,
9
+ controller: controller
10
+ )
11
+
12
+ ServicePattern::Response.new(success: true)
13
+ end
14
+
15
+ def collection
16
+ @collection ||= model_class.accessible_by(@ability, :destroy).where(model_class.primary_key => ids)
17
+ end
18
+
19
+ def ids
20
+ @commands.values.map { |command| command.fetch("primary_key") }
21
+ end
22
+ end
@@ -0,0 +1,61 @@
1
+ class ApiMaker::GenerateReactNativeApiService < ApiMaker::ApplicationService
2
+ def execute
3
+ check_if_root_folder_defined
4
+ create_root_folder
5
+ create_model_files
6
+
7
+ ServicePattern::Response.new(success: true)
8
+ end
9
+
10
+ def root_folder
11
+ @root_folder ||= ApiMaker::Configuration.current.react_native_path
12
+ end
13
+
14
+ def check_if_root_folder_defined
15
+ raise "No root folder detected" if root_folder.blank?
16
+
17
+ Dir.mkdir(model_path) unless Dir.exist?(model_path)
18
+ end
19
+
20
+ def create_root_folder
21
+ Dir.mkdir(root_folder) unless Dir.exist?(root_folder)
22
+ end
23
+
24
+ def create_model_files
25
+ model_generator_service.models.each do |model|
26
+ next if model_generator_service.ignore_model?(model)
27
+
28
+ model_content_response = ApiMaker::ModelContentGeneratorService.execute!(model: model)
29
+
30
+ if model_content_response.success?
31
+ File.open(model_file(model), "w") { |fp| fp.write(model_content_response.result) }
32
+ else
33
+ puts model_content_response.errors.join(". ")
34
+ end
35
+ end
36
+ end
37
+
38
+ def model_generator_service
39
+ @model_generator_service ||= ApiMaker::ModelsGeneratorService.new
40
+ end
41
+
42
+ def model_file(model)
43
+ resource_class = ApiMaker::MemoryStorage.current.resource_for_model(model)
44
+ File.join(model_path, "#{resource_class.short_name.underscore.dasherize}.js")
45
+ end
46
+
47
+ def model_path
48
+ @model_path ||= File.join(root_folder, "models")
49
+ end
50
+
51
+ def copy_base_model
52
+ files = %w[
53
+ api.js base-model.js cable-connection-pool.js cable-subscription.js cable-subscription-pool.js
54
+ collection.js commands-pool.js devise.js event-listener.jsx error-logger.js form-data-to-object.js logger.js
55
+ model-name.js models-response-reader.js result.js event-connection.jsx
56
+ ]
57
+ path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
58
+
59
+ copy_base_files(files, path, root_folder)
60
+ end
61
+ end
@@ -0,0 +1,96 @@
1
+ class ApiMaker::IndexCommand < ApiMaker::BaseCommand
2
+ attr_reader :params
3
+
4
+ def execute!
5
+ ApiMaker::Configuration.profile("IndexCommand execute") do
6
+ each_command do |command|
7
+ @params = command.args || {}
8
+
9
+ set_collection
10
+
11
+ if params[:count]
12
+ count = @query.count
13
+ count = count.length if count.is_a?(Hash)
14
+
15
+ command.result(count: count)
16
+ else
17
+ collection = collection_from_query(@query.fix)
18
+ response = collection.as_json
19
+ include_pagination_data(response, @query)
20
+
21
+ command.result(response)
22
+ end
23
+ end
24
+ end
25
+
26
+ ServicePattern::Response.new(success: true)
27
+ end
28
+
29
+ def filter_custom_accessible_by(collection)
30
+ return collection if params[:accessible_by].blank?
31
+
32
+ collection.accessible_by(current_ability, params[:accessible_by].to_sym)
33
+ end
34
+
35
+ def collection_from_query(collection)
36
+ ApiMaker::Configuration.profile("IndexCommand collection_from_query") do
37
+ select = parse_select(params[:select]&.permit!&.to_hash) if params[:select]
38
+
39
+ ApiMaker::CollectionSerializer.new(
40
+ ability: current_ability,
41
+ args: api_maker_args,
42
+ collection: collection,
43
+ include_param: params[:include],
44
+ select: select
45
+ ).result
46
+ end
47
+ end
48
+
49
+ def include_pagination_data(response, collection)
50
+ return if params[:page].blank?
51
+
52
+ response[:meta] = {
53
+ currentPage: collection.current_page,
54
+ totalCount: collection.try(:total_count) || collection.try(:total_entries),
55
+ totalPages: collection.total_pages
56
+ }
57
+ end
58
+
59
+ def manage_through_relationship
60
+ return if params[:through].blank?
61
+
62
+ model_class = params[:through][:model].safe_constantize
63
+ through_model = model_class.accessible_by(current_ability).find(params[:through][:id])
64
+ association = ActiveRecord::Associations::Association.new(through_model, model_class.reflections.fetch(params[:through][:reflection]))
65
+
66
+ query_through = association.scope
67
+ query_through = query_through.accessible_by(current_ability)
68
+ query_through = filter_custom_accessible_by(query_through)
69
+ query_through
70
+ end
71
+
72
+ # This converts the list of attributes to a hash that contains the data needed for the serializer (so the serializer doesn't have to do it for each model)
73
+ def parse_select(select)
74
+ new_select = {}
75
+
76
+ select.each do |model_collection_name, attributes|
77
+ model_class = model_collection_name.underscore.singularize.camelize
78
+ resource = "Resources::#{model_class}Resource".safe_constantize
79
+ raise "Resource not found for: #{model_collection_name}" unless resource
80
+
81
+ new_attributes = resource._attributes.select { |key| attributes.include?(key.to_s) }
82
+ new_select[resource.model_class] = new_attributes
83
+ end
84
+
85
+ new_select
86
+ end
87
+
88
+ def set_collection
89
+ @query = manage_through_relationship || collection
90
+ @query = @query.distinct if params[:distinct]
91
+ @query = @query.ransack(params[:q]).result
92
+ @query = @query.limit(params[:limit]) if params[:limit].present?
93
+ @query = @query.page(params[:page]) if params[:page].present?
94
+ @query = filter_custom_accessible_by(@query)
95
+ end
96
+ end
@@ -0,0 +1,22 @@
1
+ class ApiMaker::IndexCommandService < ApiMaker::CommandService
2
+ def execute
3
+ ApiMaker::IndexCommand.execute_in_thread!(
4
+ ability: ability,
5
+ args: args,
6
+ collection: collection,
7
+ commands: commands,
8
+ command_response: command_response,
9
+ controller: controller
10
+ )
11
+
12
+ ServicePattern::Response.new(success: true)
13
+ end
14
+
15
+ def collection
16
+ @collection ||= model_class.accessible_by(@ability)
17
+ end
18
+
19
+ def ids
20
+ @ids ||= @commands.values.map { |command| command.fetch("primary_key") }
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ class ApiMaker::JsMethodNamerService < ApiMaker::ApplicationService
2
+ def initialize(name:)
3
+ @name = name
4
+ end
5
+
6
+ def execute
7
+ camelized = @name.to_s.camelize
8
+ new_name = "#{camelized[0..0].downcase}#{camelized[1..camelized.length]}"
9
+ ServicePattern::Response.new(result: new_name)
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ class ApiMaker::MemberCommandService < ApiMaker::CommandService
2
+ def execute
3
+ ability_name = @command_name.to_sym
4
+ collection = model_class.accessible_by(@ability, ability_name).where(model_class.primary_key => ids)
5
+
6
+ constant.execute_in_thread!(
7
+ ability: ability,
8
+ args: args,
9
+ collection: collection,
10
+ commands: commands,
11
+ command_response: command_response,
12
+ controller: controller
13
+ )
14
+
15
+ ServicePattern::Response.new(success: true)
16
+ end
17
+
18
+ def constant
19
+ @constant ||= "Commands::#{namespace}::#{@command_name.camelize}".constantize
20
+ end
21
+
22
+ def ids
23
+ @commands.values.map { |command| command.fetch("primary_key") }
24
+ end
25
+ end
@@ -0,0 +1,108 @@
1
+ class ApiMaker::ModelContentGeneratorService < ApiMaker::ApplicationService
2
+ attr_reader :model
3
+
4
+ def initialize(model:)
5
+ @model = model
6
+ end
7
+
8
+ def execute
9
+ if resource
10
+ ServicePattern::Response.new(result: model_content)
11
+ else
12
+ ServicePattern::Response.new(errors: ["No resource defined for #{model.name}"])
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def attributes
19
+ resource._attributes.map do |attribute, _data|
20
+ {name: attribute, type: model_type(attribute)}
21
+ end
22
+ end
23
+
24
+ def collection_commands
25
+ ApiMaker::Loader.load_everything
26
+ ApiMaker::MemoryStorage.current.storage_for(resource, :collection_commands)
27
+ end
28
+
29
+ def member_commands
30
+ ApiMaker::Loader.load_everything
31
+ ApiMaker::MemoryStorage.current.storage_for(resource, :member_commands)
32
+ end
33
+
34
+ def model_content
35
+ erb = ERB.new(File.read(model_template_path))
36
+ erb.filename = File.realpath(model_template_path)
37
+ erb.result(binding)
38
+ end
39
+
40
+ def model_template_path
41
+ File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript", "model-template.js.erb")
42
+ end
43
+
44
+ def model_type(attribute_name)
45
+ model_type = model.columns_hash[attribute_name.to_s]&.type
46
+ model_type = :money if monetized_attributes.include?(attribute_name.to_s)
47
+ model_type ||= :unknown
48
+ model_type
49
+ end
50
+
51
+ def monetized_attributes
52
+ @monetized_attributes ||= @model.try(:monetized_attributes).try(:map) { |attribute| attribute[0] } || []
53
+ end
54
+
55
+ def reflections
56
+ @reflections ||= resource._relationships.map do |name, _data|
57
+ reflection = model.reflections.values.find { |reflection_i| reflection_i.name == name }
58
+ raise "Couldnt find reflection by that name: #{name}" unless reflection
59
+
60
+ reflection
61
+ end
62
+ end
63
+
64
+ def reflection_has_many_parameters(reflection)
65
+ {
66
+ reflectionName: reflection.name,
67
+ model: "{{this}}",
68
+ modelName: reflection.class_name,
69
+ modelClass: "{{modelClass}}",
70
+ targetPathName: "/api_maker/#{reflection.klass.model_name.route_key}"
71
+ }
72
+ end
73
+
74
+ def reflection_has_many_parameters_query(reflection)
75
+ if reflection.options[:through]
76
+ {
77
+ params: {
78
+ through: {
79
+ model: model.name,
80
+ id: "{{id}}",
81
+ reflection: reflection.name
82
+ }
83
+ }
84
+ }
85
+ else
86
+ {
87
+ ransack: {
88
+ "#{reflection.foreign_key}_eq" => "{{id}}"
89
+ }
90
+ }
91
+ end
92
+ end
93
+
94
+ def reflections_for_model_class_data
95
+ @reflections_for_model_class_data ||= reflections.map do |reflection|
96
+ {
97
+ className: reflection.class_name,
98
+ collectionName: ApiMaker::MemoryStorage.current.resource_for_model(reflection.klass).collection_name,
99
+ name: reflection.name,
100
+ macro: reflection.macro
101
+ }
102
+ end
103
+ end
104
+
105
+ def resource
106
+ @resource ||= ApiMaker::MemoryStorage.current.resource_for_model(@model)
107
+ end
108
+ end
@@ -0,0 +1,22 @@
1
+ class ApiMaker::ModelsFinderService < ApiMaker::ApplicationService
2
+ def execute
3
+ ServicePattern::Response.new(result: models)
4
+ end
5
+
6
+ private
7
+
8
+ def models
9
+ result = []
10
+ Dir.glob(Rails.root.join("app", "api_maker", "resources", "**", "*.rb")) do |model_path|
11
+ next unless model_path.start_with?(Rails.root.to_s)
12
+
13
+ path_name = model_path.gsub(/\A#{Regexp.escape(Rails.root.to_s)}\/app\/api_maker\/resources\//, "").gsub(/\.rb\Z/, "")
14
+ next if path_name == "application_resource"
15
+
16
+ resource_class = "Resources::#{path_name.classify}".constantize
17
+ result << resource_class.model_class
18
+ end
19
+
20
+ result
21
+ end
22
+ end
@@ -0,0 +1,104 @@
1
+ class ApiMaker::ModelsGeneratorService < ApiMaker::ApplicationService
2
+ def execute
3
+ create_base_structure
4
+ copy_base_model
5
+ copy_base_controllers
6
+
7
+ models.each do |model|
8
+ next if ignore_model?(model)
9
+
10
+ model_content_response = ApiMaker::ModelContentGeneratorService.execute(model: model)
11
+
12
+ if model_content_response.success?
13
+ File.open(model_file(model), "w") { |fp| fp.write(model_content_response.result) }
14
+ else
15
+ puts model_content_response.errors.join(". ")
16
+ end
17
+ end
18
+
19
+ ApiMaker::GenerateReactNativeApiService.execute! if ApiMaker::Configuration.current.react_native_path.present?
20
+ ServicePattern::Response.new(success: true)
21
+ end
22
+
23
+ def ignore_model?(model)
24
+ model.name.end_with?("::Translation") ||
25
+ model.name.start_with?("ActiveStorage::") ||
26
+ model.name.end_with?("::ApplicationRecord")
27
+ end
28
+
29
+ def models
30
+ ApiMaker::ModelsFinderService.execute!
31
+ end
32
+
33
+ private
34
+
35
+ def api_maker_root_path
36
+ Rails.root.join("app", "javascript", "api-maker")
37
+ end
38
+
39
+ def controller_path
40
+ Rails.root.join("app", "controllers", "api_maker")
41
+ end
42
+
43
+ def copy_base_controllers
44
+ files = %w[devise_controller.rb]
45
+ path = File.join(__dir__, "..", "..", "controllers", "api_maker")
46
+ target_path = Rails.root.join("app", "controllers", "api_maker")
47
+
48
+ copy_base_files(files, path, target_path)
49
+ end
50
+
51
+ def copy_base_model
52
+ files = %w[
53
+ api.js base-model.js cable-connection-pool.js cable-subscription.js cable-subscription-pool.js collection.js
54
+ commands-pool.js event-created.jsx custom-error.js deserializer.js devise.js event-destroyed.jsx event-emitter-listener.jsx event-listener.jsx
55
+ event-updated.jsx error-logger.js form-data-to-object.js included.js key-value-store.js logger.js model-name.js models-response-reader.js
56
+ params.js result.js event-connection.jsx paginate.jsx sort-link.jsx updated-attribute.jsx resource-routes.jsx resource-route.jsx
57
+ session-status-updater.js bootstrap/attribute-row.jsx bootstrap/attribute-rows.jsx bootstrap/card.jsx
58
+ bootstrap/checkbox.jsx bootstrap/checkboxes.jsx bootstrap/money-input.jsx bootstrap/radio-buttons.jsx
59
+ bootstrap/select.jsx bootstrap/string-input.jsx bootstrap/live-table.jsx
60
+ ]
61
+ path = File.join(__dir__, "..", "..", "..", "lib", "api_maker", "javascript")
62
+ target_path = api_maker_root_path
63
+
64
+ copy_base_files(files, path, target_path)
65
+ end
66
+
67
+ def copy_base_files(files, path, target_path)
68
+ files.each do |file|
69
+ base_model_source_path = File.join(path, file)
70
+ base_model_target_path = File.join(target_path, file)
71
+
72
+ base_model_target_dir = File.dirname(base_model_target_path)
73
+ FileUtils.mkdir_p(base_model_target_dir) unless File.exist?(base_model_target_dir)
74
+
75
+ if File.exist?(base_model_source_path)
76
+ content = File.read(base_model_source_path)
77
+ else
78
+ base_model_source_path << ".erb"
79
+ erb = ERB.new(File.read(base_model_source_path))
80
+ erb.filename = base_model_source_path
81
+ content = erb.result(binding)
82
+ end
83
+
84
+ base_model_target_path = File.join(target_path, file)
85
+
86
+ File.open(base_model_target_path, "w") do |fp|
87
+ fp.write(content)
88
+ end
89
+ end
90
+ end
91
+
92
+ def create_base_structure
93
+ # Dont remove all the files. It messes up running Webpack Dev Servers which forces you to restart all the time.
94
+ # FileUtils.rm_rf(api_maker_root_path) if File.exist?(api_maker_root_path)
95
+
96
+ FileUtils.mkdir_p(api_maker_root_path.join("models"))
97
+ FileUtils.mkdir_p(controller_path) unless File.exist?(controller_path)
98
+ end
99
+
100
+ def model_file(model)
101
+ resource_class = ApiMaker::MemoryStorage.current.resource_for_model(model)
102
+ api_maker_root_path.join("models", "#{resource_class.short_name.underscore.dasherize}.js")
103
+ end
104
+ end