module Lacerda::Conversion
Public Class Methods
ast_parsing_annotation_messages(elements, type)
click to toggle source
# File lib/lacerda/conversion.rb, line 146 def self.ast_parsing_annotation_messages(elements, type) elements.select do |element| element['element'] == 'annotation' && element['meta']['classes'].include?(type) end.map do |annotation| "#{type.capitalize} code #{annotation['attributes']['code']}: #{annotation['content']}" end end
data_structures_from_blueprint_ast(filename)
click to toggle source
The structure is of an AST is normally something like
parseResult - category # (meta => api) It seems there is always only 1 - category # (meta => dataStructures) It seems there is always only 1 - dataStructure # Bunch of data structures . . . - dataStructure . . . - annotation # Bunch of annotations(errors/warnings . . . - annotation . . .
# File lib/lacerda/conversion.rb, line 121 def self.data_structures_from_blueprint_ast(filename) # The content of the ast parsing elements = parse_result_contents_from_ast_file(filename) raise_parsing_errors(filename, elements) # We keep the content of the categories only, they could be annotations otherwise result_categories = elements.select do |element| element['element'] == 'category' end.map { |category| category['content'] }.flatten # From these categories we keep the 'dataStructures' category contents. # If there could be other types, no idea ¯\_(ツ)_/¯ data_structures_categories_contents = result_categories.select do |result_category| result_category['meta']['classes'].include?('dataStructures') end.map { |data_structures_category| data_structures_category['content'] }.flatten # From the contents of 'dataStructures' categories we keep # the 'dataStructure' elements. If there could be other types, # no idea ¯\_(ツ)_/¯ data_structures_categories_contents.select do |data_structures_content| data_structures_content['element'] == 'dataStructure' end end
mson_to_ast_json(filename)
click to toggle source
# File lib/lacerda/conversion.rb, line 154 def self.mson_to_ast_json(filename) input = filename output = filename.gsub(/\.\w+$/, '.blueprint-ast.json') # Add Data Structure section automatically mson = open(input).read unless mson[/^\#[ ]*data[ ]+structure/i] mson = "# Data Structures\n#{mson}" end result = LoungeLizard.parse(mson) File.open(output, 'w'){ |f| f.puts(result) } output end
mson_to_json_schema(options)
click to toggle source
# File lib/lacerda/conversion.rb, line 10 def self.mson_to_json_schema(options) filename = options.fetch(:filename) begin mson_to_json_schema!( filename: filename, keep_intermediary_files: options.fetch(:keep_intermediary_files, false) ) puts "OK ".green + filename if options.fetch(:verbose, true) true rescue puts "ERROR ".red + filename if options.fetch(:verbose, true) false end end
mson_to_json_schema!(options)
click to toggle source
# File lib/lacerda/conversion.rb, line 25 def self.mson_to_json_schema!(options) filename = options.fetch(:filename) # For now, we'll use the containing directory's name as a scope service_scope = File.dirname(filename).split(File::SEPARATOR).last.underscore # Parse MSON to an apiary blueprint AST # (see https://github.com/apiaryio/api-blueprint) ast_file = mson_to_ast_json(filename) # Pluck out Data structures from it data_structures = data_structures_from_blueprint_ast(ast_file) basename = File.basename(filename) file_type = basename[/(consume|publish)\.mson$/] if file_type.blank? raise Error, "Invalid filename #{basename}, can't tell if it's a publish or consume schema" end # Generate json schema from each contained data structure schema = { "$schema" => "http://json-schema.org/draft-04/schema#", "id" => file_type.gsub('.mson', '.schema.json'), "title" => service_scope, "definitions" => {}, "type" => "object", "properties" => {}, } # The json schema we're constructing contains every known # object type in the 'definitions'. So if we have definitions for # the objects User, Post and Tag, the schema will look like this: # # { # "$schema": "..." # # "definitions": { # "user": { "type": "object", "properties": { ... }} # "post": { "type": "object", "properties": { ... }} # "tag": { "type": "object", "properties": { ... }} # } # # "properties": { # "user": "#/definitions/user" # "post": "#/definitions/post" # "tag": "#/definitions/tag" # } # # } # # So when testing an object of type `user` against this schema, # we need to wrap it as: # # { # user: { # "your": "actual", # "data": "goes here" # } # } # data_structures.each do |data| id = data['content'].first['meta']['id'] json= DataStructure.new(id, data['content'], nil).to_json member = json.delete('title') schema['definitions'][member] = json schema['properties'][member] = {"$ref" => "#/definitions/#{member}"} end # Write it in a file outfile = filename.gsub(/\.\w+$/, '.schema.json') File.open(outfile, 'w'){ |f| f.puts JSON.pretty_generate(schema) } # Clean up FileUtils.rm_f(ast_file) unless options.fetch(:keep_intermediary_files, false) true end
raise_parsing_errors(mson_file, elements)
click to toggle source
# File lib/lacerda/conversion.rb, line 102 def self.raise_parsing_errors(mson_file, elements) parsing_errors = ast_parsing_errors(elements) return if parsing_errors.empty? raise Error, parsing_errors.prepend("The following errors were found in #{mson_file}:").join("\n") end
Private Class Methods
ast_parsing_errors(filename)
click to toggle source
# File lib/lacerda/conversion.rb, line 168 def self.ast_parsing_errors(filename) ast_parsing_annotation_messages(filename, 'error') end
parse_result_contents_from_ast_file(filename)
click to toggle source
Reads a file containing a json representation of a blueprint AST file, and returns the content of a parse result. It always returns an array.
# File lib/lacerda/conversion.rb, line 175 def self.parse_result_contents_from_ast_file(filename) json = JSON.parse(open(filename).read) json&.dig('content') || [] end