Finalize changes to `latest_corpus.rb`
parent
cb36bc0727
commit
8b79fdd866
286
latest_corpus.rb
286
latest_corpus.rb
|
@ -1,153 +1,143 @@
|
|||
class CorpusEmitter
|
||||
PIPE = "\n | "
|
||||
WARNING_HEADER = \
|
||||
"""
|
||||
// THIS INTERFACE WAS AUTO GENERATED ON #{Date.today}
|
||||
// DO NOT EDIT THIS FILE.
|
||||
// IT WILL BE OVERWRITTEN ON EVERY CELERYSCRIPT UPGRADE.
|
||||
|
||||
class CSArg
|
||||
TRANSLATIONS = {"integer" => "number",
|
||||
"string" => "string",
|
||||
"float" => "number",
|
||||
"boolean" => "boolean" }
|
||||
|
||||
attr_reader :name, :allowed_values
|
||||
|
||||
def initialize(name:, allowed_values:)
|
||||
@name, @allowed_values = name, allowed_values
|
||||
end
|
||||
|
||||
def camelize
|
||||
name.camelize
|
||||
end
|
||||
|
||||
def values
|
||||
allowed_values
|
||||
.map { |v| TRANSLATIONS[v] || v.camelize }
|
||||
.uniq
|
||||
.sort
|
||||
.join("\n | ")
|
||||
end
|
||||
|
||||
def to_ts
|
||||
"\n #{name}: #{values};"
|
||||
end
|
||||
"""
|
||||
HASH = Sequence::Corpus.as_json({})
|
||||
OUTPUT = [WARNING_HEADER]
|
||||
FILE_PATH = "latest_corpus.ts"
|
||||
VALUES = HASH.fetch(:values)
|
||||
VALUE_PREFIX = "CS"
|
||||
VALUES_TPL = "export type %{name} = %{type};\n"
|
||||
VALUES_OVERRIDE = HashWithIndifferentAccess.new(float: "number", integer: "number")
|
||||
# There are some rule exceptions when generating the Typescript corpus.
|
||||
FUNNY_NAMES = { "Example" => "CSExample" }
|
||||
ENUMS = HASH.fetch(:enums)
|
||||
ENUM_TPL = "export type %{name} = %{type};\n"
|
||||
ARGS = HASH
|
||||
.fetch(:args)
|
||||
.reduce(HashWithIndifferentAccess.new) do |acc, arg|
|
||||
acc[arg.fetch("name").to_s] = arg
|
||||
acc
|
||||
end
|
||||
|
||||
|
||||
class CSNode
|
||||
UNDEFINED = "undefined"
|
||||
|
||||
attr_reader :name, :allowed_args, :allowed_body_types
|
||||
|
||||
def initialize(name:, allowed_args:, allowed_body_types: [], tags:)
|
||||
@name,
|
||||
@allowed_args,
|
||||
@allowed_body_types = name, allowed_args, allowed_body_types
|
||||
end
|
||||
|
||||
def camelize
|
||||
name.camelize
|
||||
end
|
||||
|
||||
def arg_names
|
||||
allowed_args
|
||||
.map{ |x| ARGS[x] }
|
||||
.each { |x| raise "NON-EXISTENT ARG TYPE" unless x }
|
||||
.map(&:to_ts)
|
||||
.join("")
|
||||
end
|
||||
|
||||
def items_joined_by_pipe
|
||||
allowed_body_types.map(&:camelize).join(PIPE)
|
||||
end
|
||||
|
||||
def body_names
|
||||
b = items_joined_by_pipe
|
||||
(b.length > 0) ? "(#{b})[] | undefined" : UNDEFINED
|
||||
end
|
||||
|
||||
def has_body?
|
||||
body_names != UNDEFINED
|
||||
end
|
||||
|
||||
def body_type
|
||||
"export type #{camelize}BodyItem = #{items_joined_by_pipe};" if has_body?
|
||||
end
|
||||
|
||||
def body_attr
|
||||
"body?: #{ has_body? ? (camelize + "BodyItem[] | undefined") : UNDEFINED };"
|
||||
end
|
||||
|
||||
def to_ts
|
||||
<<~NODE_EXPORTS
|
||||
#{body_type}
|
||||
export interface #{camelize} {
|
||||
kind: #{name.inspect};
|
||||
args: {#{arg_names}
|
||||
};
|
||||
comment?: string | undefined;
|
||||
#{body_attr}
|
||||
}
|
||||
NODE_EXPORTS
|
||||
end
|
||||
end
|
||||
|
||||
HASH = JSON.load(open("http://#{ENV.fetch("API_HOST")}:3000/api/corpus")).deep_symbolize_keys
|
||||
ARGS = {}
|
||||
HASH[:args]
|
||||
.map { |x| CSArg.new(x) }
|
||||
.each { |x| ARGS[x.name] = x }
|
||||
NODES = HASH[:nodes].map { |x| CSNode.new(x) }
|
||||
|
||||
def const(key, val)
|
||||
"export const #{key} = #{val};"
|
||||
end
|
||||
|
||||
def enum_type(key, val, inspect = true)
|
||||
"export type #{key} = #{(inspect ? val.map(&:inspect) : val).join(PIPE)};"
|
||||
end
|
||||
|
||||
def self.generate
|
||||
self.new.generate
|
||||
end
|
||||
|
||||
def overwrite_warning_comment
|
||||
<<~COMMENT.strip
|
||||
// THIS INTERFACE WAS AUTO GENERATED ON #{Date.today}
|
||||
// DO NOT EDIT THIS FILE.
|
||||
// IT WILL BE OVERWRITTEN ON EVERY CELERYSCRIPT UPGRADE.
|
||||
COMMENT
|
||||
end
|
||||
|
||||
def generate
|
||||
result = NODES.map(&:to_ts).map(&:strip)
|
||||
result.unshift(overwrite_warning_comment)
|
||||
result.push(enum_type :CeleryNode, NODES.map(&:name).map(&:camelize), false)
|
||||
result.push(const(:LATEST_VERSION, Sequence::LATEST_VERSION))
|
||||
result.push(const :DIGITAL, CeleryScriptSettingsBag::DIGITAL)
|
||||
result.push(const :ANALOG, CeleryScriptSettingsBag::ANALOG)
|
||||
result.push(enum_type :ALLOWED_PIN_MODES,
|
||||
CeleryScriptSettingsBag::ALLOWED_PIN_MODES)
|
||||
result.push(enum_type :ALLOWED_MESSAGE_TYPES,
|
||||
CeleryScriptSettingsBag::ALLOWED_MESSAGE_TYPES)
|
||||
result.push(enum_type :ALLOWED_CHANNEL_NAMES,
|
||||
CeleryScriptSettingsBag::ALLOWED_CHANNEL_NAMES)
|
||||
result.push(enum_type :ALLOWED_OPS,
|
||||
CeleryScriptSettingsBag::ALLOWED_OPS)
|
||||
result.push(enum_type :ALLOWED_PACKAGES,
|
||||
CeleryScriptSettingsBag::ALLOWED_PACKAGES)
|
||||
result.push(enum_type :ALLOWED_AXIS, CeleryScriptSettingsBag::ALLOWED_AXIS)
|
||||
result.push(enum_type :Color, Sequence::COLORS)
|
||||
result.push(enum_type :LegalArgString, HASH[:args].map{ |x| x[:name] }.sort.uniq)
|
||||
result.push(enum_type :LegalKindString, HASH[:nodes].map{ |x| x[:name] }.sort.uniq)
|
||||
result.push(enum_type :LegalSequenceKind, CeleryScriptSettingsBag::ALLOWED_RPC_NODES.sort)
|
||||
result.push(enum_type :DataChangeType, CeleryScriptSettingsBag::ALLOWED_CHAGES)
|
||||
result.push(enum_type :PointType, CeleryScriptSettingsBag::ALLOWED_POINTER_TYPE)
|
||||
result.push(enum_type :AllowedPinTypes, CeleryScriptSettingsBag::ALLOWED_PIN_TYPES)
|
||||
result.push(enum_type :PlantStage, CeleryScriptSettingsBag::PLANT_STAGES)
|
||||
result.push(enum_type :AllowedGroupTypes, CeleryScriptSettingsBag::ALLOWED_EVERY_POINT_TYPE)
|
||||
|
||||
File.open("latest_corpus.ts", "w") do |f|
|
||||
f.write(result.join("\n\n").concat("\n"))
|
||||
end
|
||||
NODES = HASH.fetch(:nodes)
|
||||
NODE_START = [ "export type %{camel_case}BodyItem = %{body_types};",
|
||||
"/** %{docs} %{tag_docs} */",
|
||||
"export interface %{camel_case} {",
|
||||
" comment?: string | undefined;",
|
||||
' kind: "%{snake_case}";',
|
||||
" args: {", ].join("\n")
|
||||
MIDDLE_CENTER = " %{arg_name}: %{arg_values};"
|
||||
BOTTOM_END = [ " }",
|
||||
" body?: %{camel_case}BodyItem[] | undefined;",
|
||||
"}\n", ].join("\n")
|
||||
CONSTANT_DECLR_HACK = {
|
||||
LATEST_VERSION: Sequence::LATEST_VERSION,
|
||||
DIGITAL: CeleryScriptSettingsBag::DIGITAL,
|
||||
ANALOG: CeleryScriptSettingsBag::ANALOG,
|
||||
}
|
||||
CONSTANT_DECLR_HACK_TPL = "export const %{name} = %{value};\n"
|
||||
PUBLIC_NODES = [] # Filled at runtime
|
||||
def emit_constants()
|
||||
CONSTANT_DECLR_HACK.map do |(name, value)|
|
||||
konst = CONSTANT_DECLR_HACK_TPL % { name: name, value: value }
|
||||
add_to_output(konst)
|
||||
end
|
||||
end
|
||||
|
||||
CorpusEmitter.generate
|
||||
def add_to_output(string)
|
||||
OUTPUT.push(string)
|
||||
end
|
||||
|
||||
def save!
|
||||
File.open(FILE_PATH, "w") { |f| f.write(OUTPUT.join("")) }
|
||||
puts "Saved to #{FILE_PATH}"
|
||||
end
|
||||
|
||||
def name_of(thing)
|
||||
thing.fetch("name").to_s
|
||||
end
|
||||
|
||||
def emit_values
|
||||
output = VALUES.map do |val|
|
||||
real_name = name_of(val)
|
||||
capitalized = real_name.capitalize
|
||||
celerized = VALUE_PREFIX + capitalized
|
||||
FUNNY_NAMES[capitalized] = celerized
|
||||
type = VALUES_OVERRIDE.fetch(real_name, real_name)
|
||||
VALUES_TPL % { name: celerized, type: type }
|
||||
end
|
||||
.uniq
|
||||
.sort
|
||||
add_to_output(output)
|
||||
end
|
||||
|
||||
def emit_enums
|
||||
output = ENUMS.map do |enum|
|
||||
name = name_of(enum)
|
||||
type = enum.fetch("allowed_values").sort.map(&:inspect).uniq.join(" | ")
|
||||
FUNNY_NAMES[name] = name
|
||||
ENUM_TPL % { name: name, type: type }
|
||||
end
|
||||
.uniq
|
||||
.sort
|
||||
|
||||
add_to_output(output)
|
||||
end
|
||||
|
||||
def emit_nodes()
|
||||
nodes = NODES.map do |node|
|
||||
tags = node.fetch("tags").sort.uniq
|
||||
# Don't publish internal CeleryScript nodes:
|
||||
next if tags.include?(:private)
|
||||
tag_list = tags.join(", ")
|
||||
name = name_of(node).to_s
|
||||
bodies = node
|
||||
.fetch("allowed_body_types")
|
||||
.sort
|
||||
.uniq
|
||||
.map(&:to_s)
|
||||
.map(&:camelize)
|
||||
bt = bodies.any? ? "(#{bodies.join(" | ")})" : "never"
|
||||
PUBLIC_NODES.push(name.camelize)
|
||||
tpl_binding = {
|
||||
body_types: bt,
|
||||
camel_case: name.camelize,
|
||||
docs: node.fetch("docs"),
|
||||
snake_case: name,
|
||||
tag_docs: "Tag properties: #{tag_list}."
|
||||
}
|
||||
|
||||
one = NODE_START % tpl_binding
|
||||
two = node.fetch("allowed_args").sort.map do |arg|
|
||||
MIDDLE_CENTER % {
|
||||
arg_name: arg.to_s,
|
||||
arg_values: ARGS.fetch(arg)
|
||||
.fetch("allowed_values")
|
||||
.map(&:name)
|
||||
.map { |x| FUNNY_NAMES[x] || x.camelize }
|
||||
.join(" | ")
|
||||
}
|
||||
end
|
||||
three = BOTTOM_END % tpl_binding
|
||||
[one, two, three].flatten.join("\n")
|
||||
end
|
||||
.compact
|
||||
.uniq
|
||||
.join("\n")
|
||||
add_to_output(nodes)
|
||||
end
|
||||
|
||||
def emit_misc()
|
||||
types = PUBLIC_NODES.sort.uniq.join(" | ")
|
||||
tpl = "export type CeleryNode = #{types};\n"
|
||||
add_to_output(tpl)
|
||||
end
|
||||
emit_constants()
|
||||
emit_values()
|
||||
emit_enums()
|
||||
emit_nodes()
|
||||
emit_misc()
|
||||
save!
|
|
@ -1,143 +0,0 @@
|
|||
WARNING_HEADER = \
|
||||
"""
|
||||
// THIS INTERFACE WAS AUTO GENERATED ON #{Date.today}
|
||||
// DO NOT EDIT THIS FILE.
|
||||
// IT WILL BE OVERWRITTEN ON EVERY CELERYSCRIPT UPGRADE.
|
||||
|
||||
"""
|
||||
HASH = Sequence::Corpus.as_json({})
|
||||
OUTPUT = [WARNING_HEADER]
|
||||
FILE_PATH = "latest_corpus.ts"
|
||||
VALUES = HASH.fetch(:values)
|
||||
VALUE_PREFIX = "CS"
|
||||
VALUES_TPL = "export type %{name} = %{type};\n"
|
||||
VALUES_OVERRIDE = HashWithIndifferentAccess.new(float: "number", integer: "number")
|
||||
# There are some rule exceptions when generating the Typescript corpus.
|
||||
FUNNY_NAMES = { "Example" => "CSExample" }
|
||||
ENUMS = HASH.fetch(:enums)
|
||||
ENUM_TPL = "export type %{name} = %{type};\n"
|
||||
ARGS = HASH
|
||||
.fetch(:args)
|
||||
.reduce(HashWithIndifferentAccess.new) do |acc, arg|
|
||||
acc[arg.fetch("name").to_s] = arg
|
||||
acc
|
||||
end
|
||||
NODES = HASH.fetch(:nodes)
|
||||
NODE_START = [ "export type %{camel_case}BodyItem = %{body_types};",
|
||||
"/** %{docs} %{tag_docs} */",
|
||||
"export interface %{camel_case} {",
|
||||
" comment?: string | undefined;",
|
||||
' kind: "%{snake_case}";',
|
||||
" args: {", ].join("\n")
|
||||
MIDDLE_CENTER = " %{arg_name}: %{arg_values};"
|
||||
BOTTOM_END = [ " }",
|
||||
" body?: %{camel_case}BodyItem[] | undefined;",
|
||||
"}\n", ].join("\n")
|
||||
CONSTANT_DECLR_HACK = {
|
||||
LATEST_VERSION: Sequence::LATEST_VERSION,
|
||||
DIGITAL: CeleryScriptSettingsBag::DIGITAL,
|
||||
ANALOG: CeleryScriptSettingsBag::ANALOG,
|
||||
}
|
||||
CONSTANT_DECLR_HACK_TPL = "export const %{name} = %{value};\n"
|
||||
PUBLIC_NODES = [] # Filled at runtime
|
||||
def emit_constants()
|
||||
CONSTANT_DECLR_HACK.map do |(name, value)|
|
||||
konst = CONSTANT_DECLR_HACK_TPL % { name: name, value: value }
|
||||
add_to_output(konst)
|
||||
end
|
||||
end
|
||||
|
||||
def add_to_output(string)
|
||||
OUTPUT.push(string)
|
||||
end
|
||||
|
||||
def save!
|
||||
File.open(FILE_PATH, "w") { |f| f.write(OUTPUT.join("")) }
|
||||
puts "Saved to #{FILE_PATH}"
|
||||
end
|
||||
|
||||
def name_of(thing)
|
||||
thing.fetch("name").to_s
|
||||
end
|
||||
|
||||
def emit_values
|
||||
output = VALUES.map do |val|
|
||||
real_name = name_of(val)
|
||||
capitalized = real_name.capitalize
|
||||
celerized = VALUE_PREFIX + capitalized
|
||||
FUNNY_NAMES[capitalized] = celerized
|
||||
type = VALUES_OVERRIDE.fetch(real_name, real_name)
|
||||
VALUES_TPL % { name: celerized, type: type }
|
||||
end
|
||||
.uniq
|
||||
.sort
|
||||
add_to_output(output)
|
||||
end
|
||||
|
||||
def emit_enums
|
||||
output = ENUMS.map do |enum|
|
||||
name = name_of(enum)
|
||||
type = enum.fetch("allowed_values").sort.map(&:inspect).uniq.join(" | ")
|
||||
FUNNY_NAMES[name] = name
|
||||
ENUM_TPL % { name: name, type: type }
|
||||
end
|
||||
.uniq
|
||||
.sort
|
||||
|
||||
add_to_output(output)
|
||||
end
|
||||
|
||||
def emit_nodes()
|
||||
nodes = NODES.map do |node|
|
||||
tags = node.fetch("tags").sort.uniq
|
||||
# Don't publish internal CeleryScript nodes:
|
||||
next if tags.include?(:private)
|
||||
tag_list = tags.join(", ")
|
||||
name = name_of(node).to_s
|
||||
bodies = node
|
||||
.fetch("allowed_body_types")
|
||||
.sort
|
||||
.uniq
|
||||
.map(&:to_s)
|
||||
.map(&:camelize)
|
||||
bt = bodies.any? ? "(#{bodies.join(" | ")})" : "never"
|
||||
PUBLIC_NODES.push(name.camelize)
|
||||
tpl_binding = {
|
||||
body_types: bt,
|
||||
camel_case: name.camelize,
|
||||
docs: node.fetch("docs"),
|
||||
snake_case: name,
|
||||
tag_docs: "Tag properties: #{tag_list}."
|
||||
}
|
||||
|
||||
one = NODE_START % tpl_binding
|
||||
two = node.fetch("allowed_args").sort.map do |arg|
|
||||
MIDDLE_CENTER % {
|
||||
arg_name: arg.to_s,
|
||||
arg_values: ARGS.fetch(arg)
|
||||
.fetch("allowed_values")
|
||||
.map(&:name)
|
||||
.map { |x| FUNNY_NAMES[x] || x.camelize }
|
||||
.join(" | ")
|
||||
}
|
||||
end
|
||||
three = BOTTOM_END % tpl_binding
|
||||
[one, two, three].flatten.join("\n")
|
||||
end
|
||||
.compact
|
||||
.uniq
|
||||
.join("\n")
|
||||
add_to_output(nodes)
|
||||
end
|
||||
|
||||
def emit_misc()
|
||||
types = PUBLIC_NODES.sort.uniq.join(" | ")
|
||||
tpl = "export type CeleryNode = #{types};\n"
|
||||
add_to_output(tpl)
|
||||
end
|
||||
emit_constants()
|
||||
emit_values()
|
||||
emit_enums()
|
||||
emit_nodes()
|
||||
emit_misc()
|
||||
save!
|
|
@ -45,7 +45,7 @@
|
|||
"coveralls": "3.0.2",
|
||||
"enzyme": "3.8.0",
|
||||
"enzyme-adapter-react-16": "1.9.1",
|
||||
"farmbot": "7.0.0-rc8",
|
||||
"farmbot": "7.0.0-rc9",
|
||||
"farmbot-toastr": "1.0.3",
|
||||
"i18next": "12.1.0",
|
||||
"jest": "24.1.0",
|
||||
|
|
|
@ -12,7 +12,9 @@ describe CeleryScript::Corpus do
|
|||
})
|
||||
check1 = CeleryScript::Checker.new(not_ok, corpus, device)
|
||||
expect(check1.valid?).to eq(false)
|
||||
expect(check1.error.message).to include("not a type of group")
|
||||
expect(check1.error.message)
|
||||
.to include('"Veggies" is not a type of point. '\
|
||||
'Allowed values: ["GenericPointer", "ToolSlot", "Plant"]')
|
||||
end
|
||||
|
||||
it "does not all `every_location` in `move_absolute`" do
|
||||
|
|
Loading…
Reference in New Issue