foobara-typescript-react-command-form-generator 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +7 -0
- data/LICENSE.txt +8 -0
- data/README.md +52 -0
- data/lib/foobara/typescript_react_command_form_generator.rb +4 -0
- data/src/generate_typescript_react_command_form.rb +66 -0
- data/src/typescript_react_command_form_generator.rb +229 -0
- data/src/write_typescript_react_command_form_to_disk.rb +86 -0
- data/templates/CommandForm.tsx.erb +72 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 046d876be59b51bea2745841e8155702344c33560214efb6b2a6b2381a49bc72
|
4
|
+
data.tar.gz: '0955731184338275963f896dd867544cbfcc2b0bfe8886b1c54715e9bc5878ed'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6369d3afc06b6b163aa3320baa2983ff8e17b15bc561aeb2f59262d272a09d0c5af83fe5f436dca88885341586376a76543f4a8267afd1a5423db0f2f4af4aa7
|
7
|
+
data.tar.gz: 75e11096949e2439fe1daaee35c09f5670e098893c5b128a6b2ecb06cd6aadbcfd8c7b5fee79d76fdec326271eb3ac40970a693a05eee472514a6d5b2498bfa6
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
This project is dual licensed under your choice of the Apache-2.0 license and the MIT license.
|
2
|
+
|
3
|
+
Apache-2.0 License: LICENSE-APACHE.txt or https://www.apache.org/licenses/LICENSE-2.0.txt
|
4
|
+
MIT License: LICENSE-MIT.txt or https://opensource.org/licenses/MIT
|
5
|
+
|
6
|
+
This is equivalent to the following SPDX License Expression: Apache-2.0 OR MIT
|
7
|
+
|
8
|
+
Copyright (c) 2024 Miles Georgi
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Foobara::CommandGenerator
|
2
|
+
|
3
|
+
TODO: Delete this and the text below, and describe your gem
|
4
|
+
|
5
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library
|
6
|
+
into a gem. Put your Ruby code in the file `lib/foobara/typescript_react_command_form_generator`. To experiment with
|
7
|
+
that code,
|
8
|
+
run `bin/console` for an interactive prompt.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
TODO: Replace `UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG` with your gem name right after releasing it
|
13
|
+
to RubyGems.org. Please do not do it earlier due to security reasons. Alternatively, replace this section with
|
14
|
+
instructions to install your gem from git if you don't plan to release to RubyGems.org.
|
15
|
+
|
16
|
+
Install the gem and add to the application's Gemfile by executing:
|
17
|
+
|
18
|
+
$ bundle add UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
19
|
+
|
20
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
21
|
+
|
22
|
+
$ gem install UPDATE_WITH_YOUR_GEM_NAME_PRIOR_TO_RELEASE_TO_RUBYGEMS_ORG
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
TODO: Write usage instructions here
|
27
|
+
|
28
|
+
## Development
|
29
|
+
|
30
|
+
If using Foobara locally, then run the following (TODO: make this no-longer necessary.)
|
31
|
+
|
32
|
+
```bash
|
33
|
+
bundle config set local.foobara ../foobara
|
34
|
+
bundle config set disable_local_branch_check true
|
35
|
+
```
|
36
|
+
|
37
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can
|
38
|
+
also run `bin/console` for an interactive prompt that will allow you to experiment.
|
39
|
+
|
40
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
41
|
+
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
42
|
+
push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
Bug reports and pull requests are welcome on GitHub
|
47
|
+
at https://github.com/[USERNAME]/foobara-typescript-react-command-form-generator.
|
48
|
+
|
49
|
+
## License
|
50
|
+
|
51
|
+
This project is licensed under your choice of the Apache-2.0 license or the MIT license.
|
52
|
+
See [LICENSE.txt](LICENSE.txt) for more info about licensing.
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Foobara
|
2
|
+
module Generators
|
3
|
+
module TypescriptReactCommandFormGenerator
|
4
|
+
class GenerateTypescriptReactCommandForm < Foobara::RemoteGenerator::GenerateTypescript
|
5
|
+
class BadCommandNameError < Value::DataError
|
6
|
+
class << self
|
7
|
+
def context_type_declaration
|
8
|
+
{
|
9
|
+
bad_name: :string,
|
10
|
+
valid_names: [:string]
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
possible_input_error :command_name, BadCommandNameError
|
17
|
+
|
18
|
+
inputs do
|
19
|
+
raw_manifest :associative_array
|
20
|
+
manifest_url :string
|
21
|
+
command_name :string, :required
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_accessor :manifest_data, :command_manifest
|
25
|
+
|
26
|
+
def base_generator
|
27
|
+
Generators::TypescriptReactCommandFormGenerator
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute
|
31
|
+
load_manifest_if_needed
|
32
|
+
find_command_manifest
|
33
|
+
add_command_manifest_to_set_of_elements_to_generate
|
34
|
+
|
35
|
+
each_element_to_generate do
|
36
|
+
generate_element
|
37
|
+
end
|
38
|
+
|
39
|
+
paths_to_source_code
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_command_manifest
|
43
|
+
self.command_manifest = Manifest::Command.new(manifest_data, [:command, command_name])
|
44
|
+
rescue Manifest::InvalidPath
|
45
|
+
valid_keys = manifest_data["command"].keys.sort
|
46
|
+
message = "Invalid command name: #{command_name}. Expected one of #{valid_keys.join(", ")}"
|
47
|
+
error = BadCommandNameError.new(
|
48
|
+
message:,
|
49
|
+
context: {
|
50
|
+
bad_name: command_name,
|
51
|
+
valid_names: valid_keys
|
52
|
+
},
|
53
|
+
path: [:command_name]
|
54
|
+
)
|
55
|
+
|
56
|
+
add_input_error(error)
|
57
|
+
halt!
|
58
|
+
end
|
59
|
+
|
60
|
+
def add_command_manifest_to_set_of_elements_to_generate
|
61
|
+
elements_to_generate << command_manifest
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
module Foobara
|
2
|
+
module Generators
|
3
|
+
module TypescriptReactCommandFormGenerator
|
4
|
+
module Generators
|
5
|
+
class TypescriptReactCommandFormGenerator < RemoteGenerator::Services::TypescriptFromManifestBaseGenerator
|
6
|
+
class << self
|
7
|
+
def manifest_to_generator_classes(manifest)
|
8
|
+
case manifest
|
9
|
+
when Manifest::Command
|
10
|
+
[
|
11
|
+
Generators::TypescriptReactCommandFormGenerator
|
12
|
+
]
|
13
|
+
else
|
14
|
+
# :nocov:
|
15
|
+
super
|
16
|
+
# :nocov:
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def template_path
|
22
|
+
"CommandForm.tsx.erb"
|
23
|
+
end
|
24
|
+
|
25
|
+
def target_path
|
26
|
+
*parts, command_name = scoped_full_path
|
27
|
+
|
28
|
+
["forms", *parts, "#{command_name}Form.tsx"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def command_generator
|
32
|
+
@command_generator ||= RemoteGenerator::Services::CommandGenerator.new(command_manifest)
|
33
|
+
end
|
34
|
+
|
35
|
+
def model_generators(type = inputs_type, initial = true)
|
36
|
+
return @model_generators if defined?(@model_generators)
|
37
|
+
|
38
|
+
generators = if type.entity?
|
39
|
+
generator_class = RemoteGenerator::Services::UnloadedEntityGenerator
|
40
|
+
[generator_class.new(type.to_entity)]
|
41
|
+
elsif type.model?
|
42
|
+
generator_class = RemoteGenerator::Services::AtomModelGenerator
|
43
|
+
[generator_class.new(type.to_model)]
|
44
|
+
elsif type.type.to_sym == :attributes
|
45
|
+
type.attribute_declarations.values.map do |attribute_declaration|
|
46
|
+
model_generators(attribute_declaration, false)
|
47
|
+
end.flatten.uniq
|
48
|
+
elsif type.is_a?(Manifest::Array)
|
49
|
+
if type.element_type
|
50
|
+
model_generators(type.element_type, false)
|
51
|
+
end
|
52
|
+
else
|
53
|
+
# TODO: handle tuples and associative arrays
|
54
|
+
[]
|
55
|
+
end
|
56
|
+
|
57
|
+
if initial
|
58
|
+
@model_generators = generators
|
59
|
+
end
|
60
|
+
|
61
|
+
generators
|
62
|
+
end
|
63
|
+
|
64
|
+
def dependencies
|
65
|
+
[model_generators, *model_generators.map(&:dependencies)].flatten.uniq
|
66
|
+
end
|
67
|
+
|
68
|
+
def dependencies_to_generate
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
|
72
|
+
alias command_manifest relevant_manifest
|
73
|
+
|
74
|
+
def templates_dir
|
75
|
+
"#{__dir__}/../templates"
|
76
|
+
end
|
77
|
+
|
78
|
+
def inputs_class_name
|
79
|
+
"#{command_name}Inputs"
|
80
|
+
end
|
81
|
+
|
82
|
+
def result_class_name
|
83
|
+
"#{command_name}Result"
|
84
|
+
end
|
85
|
+
|
86
|
+
def error_class_name
|
87
|
+
"#{command_name}Error"
|
88
|
+
end
|
89
|
+
|
90
|
+
def command_name_english
|
91
|
+
Util.humanize(Util.underscore(command_name))
|
92
|
+
end
|
93
|
+
|
94
|
+
def non_colliding_inputs(type_declaration = inputs_type, result = [], path = [])
|
95
|
+
if type_declaration.attributes?
|
96
|
+
type_declaration.attribute_declarations.each_pair do |attribute_name, attribute_declaration|
|
97
|
+
non_colliding_inputs(attribute_declaration, result, [*path, attribute_name])
|
98
|
+
end
|
99
|
+
elsif type_declaration.entity?
|
100
|
+
# TODO: figure out how to not pass self here...
|
101
|
+
result << FlattenedAttribute.new(self, path, type_declaration.to_type.primary_key_type)
|
102
|
+
elsif type_declaration.model?
|
103
|
+
non_colliding_inputs(type_declaration.to_type.attributes_type, result, path)
|
104
|
+
elsif type_declaration.array?
|
105
|
+
if type_declaration.element_type
|
106
|
+
model_generators(type_declaration.element_type, false)
|
107
|
+
end
|
108
|
+
else
|
109
|
+
result << FlattenedAttribute.new(self, path, type_declaration)
|
110
|
+
end
|
111
|
+
|
112
|
+
result
|
113
|
+
end
|
114
|
+
|
115
|
+
def populated_inputs_object
|
116
|
+
result = {}
|
117
|
+
|
118
|
+
non_colliding_inputs.each do |flattened_attribute|
|
119
|
+
DataPath.set_value_at(result, flattened_attribute.name, flattened_attribute.path)
|
120
|
+
rescue DataPath::BadPathError
|
121
|
+
value = result
|
122
|
+
parts = flattened_attribute.path[..-2]
|
123
|
+
|
124
|
+
parts.each do |part|
|
125
|
+
value = value[part] ||= {}
|
126
|
+
end
|
127
|
+
|
128
|
+
DataPath.set_value_at(result, flattened_attribute.name, flattened_attribute.path)
|
129
|
+
end
|
130
|
+
|
131
|
+
_to_ts_string(result)
|
132
|
+
end
|
133
|
+
|
134
|
+
# TODO: come up with a better name for this and its parameter
|
135
|
+
def _to_ts_string(result, depth: 0)
|
136
|
+
if result.is_a?(::Hash)
|
137
|
+
output = "#{" " * depth}{\n"
|
138
|
+
result.each_pair.with_index do |(key, value), index|
|
139
|
+
output << "#{" " * depth} #{key}: #{_to_ts_string(value, depth: depth + 2)}"
|
140
|
+
|
141
|
+
if index != result.size - 1
|
142
|
+
output << ","
|
143
|
+
end
|
144
|
+
|
145
|
+
output << "\n"
|
146
|
+
end
|
147
|
+
|
148
|
+
"#{output}#{" " * depth}}\n"
|
149
|
+
elsif result.is_a?(::String)
|
150
|
+
result
|
151
|
+
else
|
152
|
+
# :nocov:
|
153
|
+
raise "Not sure how to handle #{result}"
|
154
|
+
# :nocov:
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
class FlattenedAttribute
|
159
|
+
attr_accessor :path, :type_declaration, :generator
|
160
|
+
|
161
|
+
def initialize(generator, path, type_declaration)
|
162
|
+
self.generator = generator
|
163
|
+
self.path = path
|
164
|
+
self.type_declaration = type_declaration
|
165
|
+
end
|
166
|
+
|
167
|
+
def name
|
168
|
+
first, *rest = path
|
169
|
+
|
170
|
+
first = Util.camelize(first)
|
171
|
+
rest = rest.map { |part| Util.camelize(part) }
|
172
|
+
|
173
|
+
[first, *rest].join
|
174
|
+
end
|
175
|
+
|
176
|
+
def name_upcase
|
177
|
+
[name[0].upcase, name[1..]].compact.join
|
178
|
+
end
|
179
|
+
|
180
|
+
def ts_type
|
181
|
+
generator.foobara_type_to_ts_type(
|
182
|
+
type_declaration,
|
183
|
+
dependency_group: generator.dependency_group
|
184
|
+
)
|
185
|
+
end
|
186
|
+
|
187
|
+
def has_default?
|
188
|
+
type_declaration.attribute? && default
|
189
|
+
end
|
190
|
+
|
191
|
+
def default
|
192
|
+
type_declaration.default
|
193
|
+
end
|
194
|
+
|
195
|
+
def ts_default
|
196
|
+
generator.value_to_ts_value(default)
|
197
|
+
end
|
198
|
+
|
199
|
+
def name_english
|
200
|
+
Util.underscore(name).gsub("_", " ")
|
201
|
+
end
|
202
|
+
|
203
|
+
def html_input
|
204
|
+
# TODO: handle boolean, etc
|
205
|
+
one_of = type_declaration.one_of
|
206
|
+
|
207
|
+
if one_of
|
208
|
+
ts_type = generator.foobara_type_to_ts_type(type_declaration)
|
209
|
+
|
210
|
+
"<select
|
211
|
+
value={#{name} ?? \"\"}
|
212
|
+
onChange={(e) => { set#{name_upcase}(e.target.value as #{ts_type}) }}
|
213
|
+
>
|
214
|
+
#{one_of.map { |value| "<option value=\"#{value}\">#{value}</option>" }.join}
|
215
|
+
</select>"
|
216
|
+
else
|
217
|
+
"<input
|
218
|
+
value={#{name} ?? \"\"}
|
219
|
+
onChange={(e) => { set#{name_upcase}(e.target.value) }}
|
220
|
+
placeholder=\"#{name_english}\"
|
221
|
+
/>"
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative "generate_typescript_react_command_form"
|
2
|
+
|
3
|
+
module Foobara
|
4
|
+
module Generators
|
5
|
+
module TypescriptReactCommandFormGenerator
|
6
|
+
class WriteTypescriptReactCommandFormToDisk < RemoteGenerator::WriteTypescriptToDisk
|
7
|
+
class NoManifestError < Foobara::RuntimeError
|
8
|
+
class << self
|
9
|
+
def context_type_declaration
|
10
|
+
{}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def generator_key
|
17
|
+
"typescript-react-command-form"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
inputs do
|
22
|
+
raw_manifest :associative_array, :allow_nil
|
23
|
+
manifest_url :string, :allow_nil
|
24
|
+
command_name :string, :required
|
25
|
+
output_directory :string
|
26
|
+
end
|
27
|
+
|
28
|
+
depends_on GenerateTypescriptReactCommandForm
|
29
|
+
|
30
|
+
def execute
|
31
|
+
load_manifest_if_needed
|
32
|
+
generate_typescript
|
33
|
+
write_all_files_to_disk
|
34
|
+
run_post_generation_tasks
|
35
|
+
|
36
|
+
stats
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate
|
40
|
+
# We don't want to fail if there is no manifest because we might be able to load it from manifest.json
|
41
|
+
end
|
42
|
+
|
43
|
+
def raw_manifest
|
44
|
+
@raw_manifest || inputs[:raw_manifest]
|
45
|
+
end
|
46
|
+
|
47
|
+
def load_manifest_if_needed
|
48
|
+
if !raw_manifest && !manifest_url
|
49
|
+
manifest_path = "#{output_directory}/manifest.json"
|
50
|
+
if File.exist?(manifest_path)
|
51
|
+
@raw_manifest = JSON.parse(File.read(manifest_path))
|
52
|
+
else
|
53
|
+
message = "Because there is no manifest.json to read manifest from, " \
|
54
|
+
"you must either provide a manifest_url or raw_manifest."
|
55
|
+
error = NoManifestError.new(message:, context: {})
|
56
|
+
|
57
|
+
add_runtime_error(error)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def output_directory
|
63
|
+
inputs[:output_directory] || default_output_directory
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_output_directory
|
67
|
+
# :nocov:
|
68
|
+
"src/domains"
|
69
|
+
# :nocov:
|
70
|
+
end
|
71
|
+
|
72
|
+
def generate_typescript
|
73
|
+
# TODO: we need a way to allow values to be nil in type declarations
|
74
|
+
inputs = raw_manifest ? { raw_manifest: } : { manifest_url: }
|
75
|
+
inputs.merge!(command_name:)
|
76
|
+
|
77
|
+
self.paths_to_source_code = run_subcommand!(GenerateTypescriptReactCommandForm, inputs)
|
78
|
+
end
|
79
|
+
|
80
|
+
def run_post_generation_tasks
|
81
|
+
eslint_fix
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import React, { useState } from 'react'
|
2
|
+
|
3
|
+
import { Outcome } from "<%= path_to_root %>/base/Outcome"
|
4
|
+
|
5
|
+
import { <%= command_name %> } from "<%= path_to_root %><%= command_generator.import_path %>"
|
6
|
+
import <%= inputs_class_name %> from "<%= path_to_root %><%= command_generator.import_path %>/Inputs"
|
7
|
+
import <%= result_class_name %> from "<%= path_to_root %><%= command_generator.import_path %>/Result"
|
8
|
+
import { Error as <%= error_class_name %> } from "<%= path_to_root %><%= command_generator.import_path %>/Errors"
|
9
|
+
|
10
|
+
export default function <%= command_name %>Form (): JSX.Element {
|
11
|
+
<% non_colliding_inputs.each do |flattened_attribute| %>
|
12
|
+
<% if flattened_attribute.has_default? %>
|
13
|
+
const [<%= flattened_attribute.name %>, set<%= flattened_attribute.name_upcase %>] = useState<<%= flattened_attribute.ts_type %>>(<%= flattened_attribute.ts_default %>)
|
14
|
+
<% else %>
|
15
|
+
const [<%= flattened_attribute.name %>, set<%= flattened_attribute.name_upcase %>] = useState<<%= flattened_attribute.ts_type %> | undefined>(undefined)
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
const [result, setResult] = useState<string | null>(null)
|
20
|
+
const [error, setError] = useState<string | null>(null)
|
21
|
+
|
22
|
+
function toVoid (fn: () => Promise<void>): () => void {
|
23
|
+
return (): void => {
|
24
|
+
void (async (): Promise<void> => { await fn() })()
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
const run = toVoid(async (): Promise<void> => {
|
29
|
+
<% non_colliding_inputs.each do |flattened_attribute| %>
|
30
|
+
if (<%= flattened_attribute.name %> == null) {
|
31
|
+
// TODO: perform some kind of validation error
|
32
|
+
return
|
33
|
+
}
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
const inputs: <%= inputs_class_name %> = <%= populated_inputs_object %>
|
37
|
+
|
38
|
+
const command = new <%= command_name %>(inputs)
|
39
|
+
|
40
|
+
try {
|
41
|
+
setResult("Thinking...")
|
42
|
+
setError(null)
|
43
|
+
const outcome: Outcome<<%= result_class_name %>, <%= error_class_name %>> = await command.run()
|
44
|
+
|
45
|
+
if (outcome.isSuccess()) {
|
46
|
+
const result: <%= result_class_name %> = outcome.result
|
47
|
+
setResult(typeof result === 'string' ? result : JSON.stringify(result))
|
48
|
+
} else {
|
49
|
+
setError(outcome.errorMessage)
|
50
|
+
setResult(null)
|
51
|
+
}
|
52
|
+
} catch (error) {
|
53
|
+
setError('Error executing command')
|
54
|
+
setResult(null)
|
55
|
+
}
|
56
|
+
})
|
57
|
+
|
58
|
+
return (
|
59
|
+
<div className="CommandForm">
|
60
|
+
<div>
|
61
|
+
<% non_colliding_inputs.each do |flattened_attribute| %>
|
62
|
+
<%= flattened_attribute.html_input %>
|
63
|
+
<% end %>
|
64
|
+
|
65
|
+
<button onClick={run}><%= command_name_english %></button>
|
66
|
+
</div>
|
67
|
+
|
68
|
+
{(result != null) && <p>{result}</p>}
|
69
|
+
{(error != null) && <p className="error-message">{error}</p>}
|
70
|
+
</div>
|
71
|
+
)
|
72
|
+
}
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: foobara-typescript-react-command-form-generator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Miles Georgi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-06-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: foobara
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: foobara-files-generator
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: foobara-typescript-remote-command-generator
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- azimux@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- CHANGELOG.md
|
63
|
+
- LICENSE.txt
|
64
|
+
- README.md
|
65
|
+
- lib/foobara/typescript_react_command_form_generator.rb
|
66
|
+
- src/generate_typescript_react_command_form.rb
|
67
|
+
- src/typescript_react_command_form_generator.rb
|
68
|
+
- src/write_typescript_react_command_form_to_disk.rb
|
69
|
+
- templates/CommandForm.tsx.erb
|
70
|
+
homepage: https://github.com/foobara/generators-typescript-react-command-form-generator
|
71
|
+
licenses:
|
72
|
+
- Apache-2.0
|
73
|
+
- MIT
|
74
|
+
metadata:
|
75
|
+
homepage_uri: https://github.com/foobara/generators-typescript-react-command-form-generator
|
76
|
+
source_code_uri: https://github.com/foobara/generators-typescript-react-command-form-generator
|
77
|
+
changelog_uri: https://github.com/foobara/generators-typescript-react-command-form-generator/blob/main/CHANGELOG.md
|
78
|
+
rubygems_mfa_required: 'true'
|
79
|
+
post_install_message:
|
80
|
+
rdoc_options: []
|
81
|
+
require_paths:
|
82
|
+
- lib
|
83
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 3.2.2
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
requirements: []
|
94
|
+
rubygems_version: 3.4.10
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: Generates Typescript React forms for Foobara remote commands
|
98
|
+
test_files: []
|