foobara-typescript-remote-command-generator 0.0.1

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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +7 -0
  3. data/LICENSE-APACHE.txt +202 -0
  4. data/LICENSE-MIT.txt +21 -0
  5. data/LICENSE.txt +8 -0
  6. data/README.md +55 -0
  7. data/lib/foobara/typescript_remote_command_generator.rb +13 -0
  8. data/src/remote_generator/association_depth.rb +11 -0
  9. data/src/remote_generator/generate_typescript.rb +85 -0
  10. data/src/remote_generator/services/aggregate_entity_generator.rb +49 -0
  11. data/src/remote_generator/services/aggregate_model_generator.rb +53 -0
  12. data/src/remote_generator/services/atom_entity_generator.rb +47 -0
  13. data/src/remote_generator/services/atom_model_generator.rb +49 -0
  14. data/src/remote_generator/services/command_errors_generator.rb +36 -0
  15. data/src/remote_generator/services/command_errors_index_generator.rb +31 -0
  16. data/src/remote_generator/services/command_generator.rb +41 -0
  17. data/src/remote_generator/services/command_inputs_generator.rb +33 -0
  18. data/src/remote_generator/services/command_manifest_generator.rb +13 -0
  19. data/src/remote_generator/services/command_result_generator.rb +80 -0
  20. data/src/remote_generator/services/dependency_group.rb +137 -0
  21. data/src/remote_generator/services/domain_config_generator.rb +21 -0
  22. data/src/remote_generator/services/domain_generator.rb +63 -0
  23. data/src/remote_generator/services/domain_manifest_generator.rb +17 -0
  24. data/src/remote_generator/services/entity_generator.rb +43 -0
  25. data/src/remote_generator/services/entity_manifest_generator.rb +10 -0
  26. data/src/remote_generator/services/entity_variants_generator.rb +47 -0
  27. data/src/remote_generator/services/error_generator.rb +68 -0
  28. data/src/remote_generator/services/loaded_entity_generator.rb +27 -0
  29. data/src/remote_generator/services/manifest_generator.rb +13 -0
  30. data/src/remote_generator/services/model_generator.rb +84 -0
  31. data/src/remote_generator/services/model_manifest_generator.rb +11 -0
  32. data/src/remote_generator/services/model_variants_generator.rb +35 -0
  33. data/src/remote_generator/services/organization_config_generator.rb +21 -0
  34. data/src/remote_generator/services/organization_generator.rb +41 -0
  35. data/src/remote_generator/services/organization_manifest_generator.rb +17 -0
  36. data/src/remote_generator/services/processor_class_generator.rb +18 -0
  37. data/src/remote_generator/services/root_manifest_generator.rb +13 -0
  38. data/src/remote_generator/services/typescript_from_manifest_base_generator.rb +293 -0
  39. data/src/remote_generator/services/unloaded_entity_generator.rb +25 -0
  40. data/src/remote_generator/write_typescript_to_disk.rb +78 -0
  41. data/src/remote_generator.rb +5 -0
  42. data/templates/Command/Errors.ts.erb +11 -0
  43. data/templates/Command/Inputs.ts.erb +5 -0
  44. data/templates/Command/Result.ts.erb +7 -0
  45. data/templates/Command/errors/index.ts.erb +3 -0
  46. data/templates/Command.ts.erb +11 -0
  47. data/templates/Domain/config.ts.erb +16 -0
  48. data/templates/Domain.ts.erb +17 -0
  49. data/templates/Entity/Aggregate.ts.erb +18 -0
  50. data/templates/Entity/Ambiguous.ts.erb +30 -0
  51. data/templates/Entity/Atom.ts.erb +18 -0
  52. data/templates/Entity/Loaded.ts.erb +14 -0
  53. data/templates/Entity/Unloaded.ts.erb +18 -0
  54. data/templates/EntityVariants.ts.erb +40 -0
  55. data/templates/Error.ts.erb +8 -0
  56. data/templates/Model/Aggregate.ts.erb +12 -0
  57. data/templates/Model/Atom.ts.erb +12 -0
  58. data/templates/Model/Model.ts.erb +18 -0
  59. data/templates/ModelVariants.ts.erb +26 -0
  60. data/templates/Organization/config.ts.erb +16 -0
  61. data/templates/Organization.ts.erb +8 -0
  62. data/templates/base/DataPath.ts +49 -0
  63. data/templates/base/Entity.ts +87 -0
  64. data/templates/base/Error.ts +29 -0
  65. data/templates/base/Model.ts +24 -0
  66. data/templates/base/Outcome.ts +42 -0
  67. data/templates/base/RemoteCommand.ts +87 -0
  68. metadata +142 -0
@@ -0,0 +1,84 @@
1
+ require_relative "typescript_from_manifest_base_generator"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class Services
6
+ class ModelGenerator < TypescriptFromManifestBaseGenerator
7
+ class << self
8
+ def new(relevant_manifest)
9
+ return super unless self == ModelGenerator
10
+
11
+ if relevant_manifest.entity?
12
+ EntityGenerator.new(relevant_manifest)
13
+ else
14
+ super
15
+ end
16
+ end
17
+ end
18
+
19
+ alias model_manifest relevant_manifest
20
+
21
+ def target_path
22
+ [*domain.scoped_full_path, "types", model_name, "#{model_name}.ts"]
23
+ end
24
+
25
+ def template_path
26
+ ["Model", "Model.ts.erb"]
27
+ end
28
+
29
+ def scoped_full_path(points = nil)
30
+ full_path = model_manifest.scoped_full_path
31
+
32
+ if points
33
+ start_at = full_path.size - points - 1
34
+ full_path[start_at..]
35
+ else
36
+ full_path
37
+ end
38
+ end
39
+
40
+ def model_name(points = nil)
41
+ if points
42
+ scoped_full_path(points).join(".")
43
+ else
44
+ scoped_path.join(".")
45
+ end
46
+ end
47
+
48
+ # Do models have associations??
49
+ def model_generators
50
+ types_depended_on.select(&:model?).map do |model|
51
+ Services::ModelGenerator.new(model)
52
+ end
53
+ end
54
+
55
+ def dependencies
56
+ model_generators
57
+ end
58
+
59
+ def model_name_downcase
60
+ model_name[0].downcase + model_name[1..]
61
+ end
62
+
63
+ def attributes_type_ts_type
64
+ association_depth = AssociationDepth::AMBIGUOUS
65
+ foobara_type_to_ts_type(attributes_type, association_depth:, dependency_group:)
66
+ end
67
+
68
+ def atom_attributes_ts_type
69
+ association_depth = AssociationDepth::ATOM
70
+ foobara_type_to_ts_type(attributes_type, association_depth:, dependency_group:)
71
+ end
72
+
73
+ def aggregate_attributes_ts_type
74
+ association_depth = AssociationDepth::AGGREGATE
75
+ foobara_type_to_ts_type(attributes_type, association_depth:, dependency_group:)
76
+ end
77
+
78
+ def attribute_names
79
+ attributes_type.attribute_names
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,11 @@
1
+ module Foobara
2
+ module RemoteGenerator
3
+ class Services
4
+ class ModelManifestGenerator < ManifestGenerator
5
+ def target_path
6
+ [*domain.scoped_full_path, "types", model_name, "manifest.json"]
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,35 @@
1
+ module Foobara
2
+ module RemoteGenerator
3
+ class Services
4
+ class ModelVariantsGenerator < ModelGenerator
5
+ def target_path
6
+ [*domain.scoped_full_path, "types", "#{model_name}.ts"]
7
+ end
8
+
9
+ def template_path
10
+ "ModelVariants.ts.erb"
11
+ end
12
+
13
+ def model_generator
14
+ ModelGenerator.new(model_manifest)
15
+ end
16
+
17
+ def atom_model_generator
18
+ AtomModelGenerator.new(model_manifest)
19
+ end
20
+
21
+ def aggregate_model_generator
22
+ AggregateModelGenerator.new(model_manifest)
23
+ end
24
+
25
+ def dependencies
26
+ if has_associations?
27
+ [model_generator, atom_model_generator, aggregate_model_generator]
28
+ else
29
+ [model_generator]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "organization_generator"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class Services
6
+ class OrganizationConfigGenerator < OrganizationGenerator
7
+ def target_path
8
+ [*super[0..-2], "config.ts"]
9
+ end
10
+
11
+ def template_path
12
+ "Organization/config.ts.erb"
13
+ end
14
+
15
+ def dependencies
16
+ []
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ require_relative "typescript_from_manifest_base_generator"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class Services
6
+ class OrganizationGenerator < TypescriptFromManifestBaseGenerator
7
+ alias organization_manifest relevant_manifest
8
+
9
+ def import_destructure
10
+ "* as #{organization_name}"
11
+ end
12
+
13
+ def target_path
14
+ if global?
15
+ ["GlobalOrganization", "index.ts"]
16
+ else
17
+ [*scoped_full_path, "index.ts"]
18
+ end
19
+ end
20
+
21
+ def template_path
22
+ "Organization.ts.erb"
23
+ end
24
+
25
+ def domain_generators
26
+ @domain_generators ||= organization_manifest.domains.map do |domain_manifest|
27
+ DomainGenerator.new(domain_manifest)
28
+ end
29
+ end
30
+
31
+ def dependencies
32
+ domain_generators
33
+ end
34
+
35
+ def organization_name
36
+ scoped_short_name || "GlobalOrganization"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ require_relative "manifest_generator"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class Services
6
+ class OrganizationManifestGenerator < ManifestGenerator
7
+ def target_path
8
+ if global?
9
+ ["GlobalOrganization", "manifest.json"]
10
+ else
11
+ [*scoped_full_path, "manifest.json"]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,18 @@
1
+ require_relative "typescript_from_manifest_base_generator"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class Services
6
+ class ProcessorClassGenerator < TypescriptFromManifestBaseGenerator
7
+ alias processor_class_manifest relevant_manifest
8
+
9
+ def target_path
10
+ *path, basename = scoped_full_path
11
+ basename = "#{basename}.ts"
12
+
13
+ ["base", "processors", *path, basename]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ require_relative "manifest_generator"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class Services
6
+ class RootManifestGenerator < ManifestGenerator
7
+ def target_path
8
+ ["manifest.json"]
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,293 @@
1
+ # Where to put files?
2
+ # let's examine an error...
3
+ # if an error belongs to a command, let's put it in <command path>/errors/<error_name>.ts
4
+ # if an error belongs to a domain, let's put it in <domain path>/errors/<error_name>.ts
5
+ # if an error belongs to an organization, let's put it in <organization path>/errors/<error_name>.ts
6
+ # if an error belongs to a base processor, let's put it in base/processors/<processor path>/<error_name>.ts
7
+ # if an error belongs to nothing, let's put it in errors/<error_name>.ts
8
+ #
9
+ # so what is the official logic?
10
+ # if parent is a domain or org or nil,
11
+ # then we need to insert "errors" before the last element in the scoped_path.
12
+ # This is to help make the commands more first-class.
13
+ # otherwise, the thing will already be out of site. We could prepend the path with "base" and <parent_category>.
14
+ #
15
+ # Might just be safer though to leverage the parent's target_dir.
16
+ #
17
+ # So that logic would be...
18
+ # if parent is domain, nil, or org:
19
+ # <parent_target_dir>/errors/<error_name>.ts
20
+ # else
21
+ # <parent_target_dir>/<error_name>.ts
22
+
23
+ module Foobara
24
+ module RemoteGenerator
25
+ class Services
26
+ class TypescriptFromManifestBaseGenerator < Foobara::FilesGenerator
27
+ class << self
28
+ def manifest_to_generator_classes(manifest)
29
+ case manifest
30
+ when Manifest::Command
31
+ [
32
+ Services::CommandGenerator,
33
+ Services::CommandInputsGenerator,
34
+ Services::CommandResultGenerator,
35
+ Services::CommandErrorsGenerator,
36
+ Services::CommandErrorsIndexGenerator,
37
+ Services::CommandManifestGenerator
38
+ ]
39
+ when Manifest::Domain
40
+ [
41
+ Services::DomainGenerator,
42
+ Services::DomainConfigGenerator,
43
+ Services::DomainManifestGenerator
44
+ ]
45
+ when Manifest::Organization
46
+ [
47
+ Services::OrganizationGenerator,
48
+ Services::OrganizationConfigGenerator,
49
+ Services::OrganizationManifestGenerator
50
+ ]
51
+ when Manifest::Entity
52
+ [
53
+ Services::EntityGenerator,
54
+ Services::EntityVariantsGenerator,
55
+ Services::EntityManifestGenerator
56
+ ]
57
+ when Manifest::Model
58
+ [
59
+ Services::ModelGenerator,
60
+ Services::ModelVariantsGenerator,
61
+ Services::ModelManifestGenerator
62
+ ]
63
+ when Manifest::Error
64
+ Services::ErrorGenerator
65
+ when Manifest::ProcessorClass
66
+ Services::ProcessorClassGenerator
67
+ when Manifest::RootManifest
68
+ Services::RootManifestGenerator
69
+ else
70
+ # :nocov:
71
+ raise "Not sure how build a generator for a #{manifest}"
72
+ # :nocov:
73
+ end
74
+ end
75
+ end
76
+
77
+ def initialize(relevant_manifest)
78
+ unless relevant_manifest.is_a?(Manifest::BaseManifest)
79
+ # :nocov:
80
+ raise ArgumentError, "Expected a Foobara::Manifest, got #{relevant_manifest.class}"
81
+ # :nocov:
82
+ end
83
+
84
+ super
85
+ end
86
+
87
+ def templates_dir
88
+ "#{__dir__}/../../../templates"
89
+ end
90
+
91
+ def parent
92
+ if relevant_manifest.parent
93
+ generator_for(relevant_manifest.parent)
94
+ end
95
+ end
96
+
97
+ def dependency_group
98
+ @dependency_group ||= begin
99
+ generators = dependencies.map do |dependency|
100
+ generator_for(dependency)
101
+ end
102
+
103
+ DependencyGroup.new(generators, name: scoped_full_path.join("."))
104
+ end
105
+ end
106
+
107
+ def dependency_roots
108
+ unless dependency_group
109
+ # :nocov:
110
+ raise "This generator was created without a " \
111
+ "dependency_group and therefore cannot call #{__method__}"
112
+ # :nocov:
113
+ end
114
+
115
+ dependency_group.non_colliding_dependency_roots.sort_by(&:scoped_full_name)
116
+ end
117
+
118
+ def ts_instance_name
119
+ ts_instance_path.join(".")
120
+ end
121
+
122
+ def ts_instance_path
123
+ scoped_path
124
+ end
125
+
126
+ def ts_instance_full_name
127
+ ts_instance_full_path.join(".")
128
+ end
129
+
130
+ def ts_instance_full_path
131
+ scoped_full_path
132
+ end
133
+
134
+ def ts_type_full_path
135
+ ts_instance_full_path
136
+ end
137
+
138
+ foobara_delegate :organization_name,
139
+ :domain_name,
140
+ to: :relevant_manifest
141
+
142
+ def import_path
143
+ if import_path_array.size == 1
144
+ "./#{import_path_array.first}"
145
+ else
146
+ import_path_array.join("/")
147
+ end
148
+ end
149
+
150
+ def import_destructure
151
+ "{ #{scoped_name} }"
152
+ end
153
+
154
+ def import_path_array
155
+ path = if target_path.last == "index.ts"
156
+ target_path[0..-2]
157
+ else
158
+ target_path
159
+ end
160
+
161
+ path[-1] = path.last.gsub(/\.ts$/, "")
162
+
163
+ path
164
+ end
165
+
166
+ def value_to_ts_value(value)
167
+ case value
168
+ when ::String, Numeric
169
+ value.inspect
170
+ when ::Symbol
171
+ value.to_s.inspect
172
+ else
173
+ # :nocov:
174
+ raise "Not sure how to represent #{value} in typescript. Maybe implement it."
175
+ # :nocov:
176
+ end
177
+ end
178
+
179
+ # TODO: relocate this to a more reusable place
180
+ def foobara_type_to_ts_type(
181
+ type_declaration,
182
+ dependency_group: self.dependency_group,
183
+ name: nil,
184
+ association_depth: AssociationDepth::AMBIGUOUS,
185
+ initial: true
186
+ )
187
+ if type_declaration.is_a?(Manifest::Error)
188
+ error_generator = generator_for(type_declaration)
189
+ return dependency_group.non_colliding_type(error_generator)
190
+ end
191
+
192
+ type_string = if type_declaration.is_a?(Manifest::Attributes)
193
+ ts_type = attributes_to_ts_type(type_declaration, association_depth:, dependency_group:)
194
+
195
+ if name
196
+ return "interface #{name} #{ts_type}"
197
+ else
198
+ ts_type
199
+ end
200
+ elsif type_declaration.is_a?(Manifest::Array)
201
+ # TODO: which association_depth do we pass here?
202
+ ts_type = foobara_type_to_ts_type(
203
+ type_declaration.element_type,
204
+ association_depth:,
205
+ dependency_group:,
206
+ initial: false
207
+ )
208
+ "#{ts_type}[]"
209
+ else
210
+ type_symbol = type_declaration.type
211
+
212
+ case type_symbol
213
+ when "string", "boolean"
214
+ type_symbol
215
+ when "number", "integer", "float"
216
+ "number"
217
+ # TODO: should apply relevant processors to make email a real email type instead of "string"
218
+ when "symbol", "email"
219
+ "string"
220
+ when "duck"
221
+ "any"
222
+ when "datetime"
223
+ "Date"
224
+ else
225
+ if type_declaration.model?
226
+ model_to_ts_model_name(type_declaration, association_depth:, initial:)
227
+ end
228
+ end
229
+ end
230
+
231
+ if type_string
232
+ if type_declaration.one_of
233
+ type_string = type_declaration.one_of.map(&:inspect).join(" | ")
234
+ end
235
+
236
+ if type_declaration.allows_nil?
237
+ type_string = "#{type_string} | null"
238
+ end
239
+
240
+ name ? "#{name} = #{type_string}" : type_string
241
+ else
242
+ # :nocov:
243
+ raise "Not sure how to convert #{type_declaration} to a TS type"
244
+ # :nocov:
245
+ end
246
+ end
247
+
248
+ def attributes_to_ts_type(attributes, dependency_group:, association_depth: AssociationDepth::AMBIGUOUS)
249
+ guts = attributes.attribute_declarations.map do |attribute_name, attribute_declaration|
250
+ " #{attribute_name}#{"?" unless attributes.required?(attribute_name)}: #{
251
+ foobara_type_to_ts_type(attribute_declaration, dependency_group:, association_depth:, initial: false)
252
+ }"
253
+ end.join("\n")
254
+
255
+ "{\n#{guts}\n}"
256
+ end
257
+
258
+ def model_to_ts_model_name(model, association_depth: AssociationDepth::AMBIGUOUS, initial: true)
259
+ model = model.to_type if model.is_a?(Manifest::TypeDeclaration)
260
+
261
+ generator_class = case association_depth
262
+ when AssociationDepth::AMBIGUOUS
263
+ Services::ModelGenerator
264
+ when AssociationDepth::ATOM
265
+ if !initial && model.entity?
266
+ Services::UnloadedEntityGenerator
267
+ else
268
+ Services::AtomModelGenerator
269
+ end
270
+ when AssociationDepth::AGGREGATE
271
+ Services::AggregateModelGenerator
272
+ else
273
+ # :nocov:
274
+ raise "Bad association_depth: #{association_depth}"
275
+ # :nocov:
276
+ end
277
+
278
+ generator = generator_class.new(model)
279
+
280
+ dependency_group.non_colliding_type(generator)
281
+ end
282
+
283
+ def ==(other)
284
+ self.class == other.class && path == other.path && root_manifest == other.root_manifest
285
+ end
286
+
287
+ def hash
288
+ path.hash
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,25 @@
1
+ module Foobara
2
+ module RemoteGenerator
3
+ class Services
4
+ class UnloadedEntityGenerator < EntityGenerator
5
+ def target_path
6
+ [*domain.scoped_full_path, "types", entity_name, "Unloaded.ts"]
7
+ end
8
+
9
+ def template_path
10
+ ["Entity", "Unloaded.ts.erb"]
11
+ end
12
+
13
+ def ts_instance_path
14
+ *prefix, name = super
15
+ [*prefix, "Unloaded#{name}"]
16
+ end
17
+
18
+ def ts_instance_full_path
19
+ *prefix, name = super
20
+ [*prefix, "Unloaded#{name}"]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,78 @@
1
+ require_relative "generate_typescript"
2
+
3
+ module Foobara
4
+ module RemoteGenerator
5
+ class WriteTypescriptToDisk < Generators::WriteGeneratedFilesToDisk
6
+ class << self
7
+ def generator_key
8
+ "typescript-remote-commands"
9
+ end
10
+ end
11
+
12
+ # TODO: shouldn't have to qualify DataError like this
13
+ class MissingManifestError < Value::DataError
14
+ class << self
15
+ def context_type_declaration
16
+ {}
17
+ end
18
+ end
19
+ end
20
+
21
+ possible_error MissingManifestError
22
+
23
+ inputs do
24
+ raw_manifest :associative_array, :allow_nil
25
+ manifest_url :string, :allow_nil
26
+ # TODO: should be able to delete this and inherit it
27
+ output_directory :string, default: "src/domains"
28
+ end
29
+
30
+ depends_on GenerateTypescript
31
+
32
+ def execute
33
+ generate_typescript
34
+ generate_generated_files_json
35
+ delete_old_files_if_needed
36
+ write_all_files_to_disk
37
+ run_post_generation_tasks
38
+
39
+ stats
40
+ end
41
+
42
+ def validate
43
+ if raw_manifest.nil? && manifest_url.nil?
44
+ add_input_error(
45
+ MissingManifestError.new(
46
+ message: "Must provide either raw_manifest or manifest_url",
47
+ context: {}
48
+ )
49
+ )
50
+ end
51
+ end
52
+
53
+ def generate_typescript
54
+ # TODO: we need a way to allow values to be nil in type declarations
55
+ inputs = raw_manifest ? { raw_manifest: } : { manifest_url: }
56
+
57
+ self.paths_to_source_code = run_subcommand!(GenerateTypescript, inputs)
58
+ end
59
+
60
+ def run_post_generation_tasks
61
+ eslint_fix
62
+ end
63
+
64
+ def eslint_fix
65
+ cmd = "npx eslint 'src/**/*.{js,jsx,ts,tsx}' --fix"
66
+
67
+ Open3.popen3(cmd) do |_stdin, _stdout, stderr, wait_thr|
68
+ exit_status = wait_thr.value
69
+ unless exit_status.success?
70
+ # :nocov:
71
+ warn "WARNING: could not #{cmd}\n#{stderr.read}"
72
+ # :nocov:
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,5 @@
1
+ module Foobara
2
+ module RemoteGenerator
3
+ foobara_domain!
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ <% dependency_roots.each do |dependency_root| %>
2
+ import <%= dependency_root.import_destructure %> from "<%= path_to_root %><%= dependency_root.import_path %>"
3
+ <% end %>
4
+
5
+ export interface PossibleErrors {
6
+ <% possible_errors.keys.sort.each do |key| %>
7
+ "<%= key %>": <%= foobara_type_to_ts_type(possible_errors[key].error, dependency_group:) %>,
8
+ <% end %>
9
+ }
10
+
11
+ export type Error = <%= error_type_union %>
@@ -0,0 +1,5 @@
1
+ <% dependency_roots.each do |dependency_root| %>
2
+ import <%= dependency_root.import_destructure %> from "<%= path_to_root %><%= dependency_root.import_path %>"
3
+ <% end %>
4
+
5
+ export default <%= foobara_type_to_ts_type(inputs_type, name: "Inputs", dependency_group:) %>
@@ -0,0 +1,7 @@
1
+ <% dependency_roots.each do |dependency_root| %>
2
+ import { <%= dependency_root.ts_instance_name %> } from "<%= path_to_root %><%= dependency_root.import_path %>"
3
+ <% end %>
4
+
5
+ type Result = <%= foobara_type_to_ts_type(result_type, dependency_group:, association_depth:) %>
6
+
7
+ export default Result
@@ -0,0 +1,3 @@
1
+ <% errors_in_this_namespace.each do |error_generator| %>
2
+ export <%= error_generator.import_destructure %> from "<%= path_to_root %><%= error_generator.import_path %>"
3
+ <% end %>