admiral-tools-figma 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 (57) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +1 -0
  3. data/admiral-tools-figma.gemspec +9 -0
  4. data/admiraltools/actions/figma_download_images.rb +116 -0
  5. data/admiraltools/actions/figma_generate_styles.rb +77 -0
  6. data/admiraltools/actions/figma_get_image_links.rb +139 -0
  7. data/admiraltools/actions/figma_get_styles.rb +90 -0
  8. data/admiraltools/helper/admiraltools_helper.rb +18 -0
  9. data/admiraltools/helper/figma/figma_client/figma_client.rb +193 -0
  10. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_color.rb +35 -0
  11. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_component.rb +58 -0
  12. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_components_styles_meta.rb +30 -0
  13. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_frame_info.rb +46 -0
  14. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_node.rb +43 -0
  15. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_paint.rb +32 -0
  16. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_style.rb +48 -0
  17. data/admiraltools/helper/figma/figma_client/models/api/primitives/figma_type_style.rb +56 -0
  18. data/admiraltools/helper/figma/figma_client/models/api/results/figma_components_styles_result.rb +36 -0
  19. data/admiraltools/helper/figma/figma_client/models/api/results/figma_images_result.rb +25 -0
  20. data/admiraltools/helper/figma/figma_client/models/api/results/figma_nodes_result.rb +52 -0
  21. data/admiraltools/helper/figma/figma_client/models/domain/converters/figma_to_domain_converter.rb +98 -0
  22. data/admiraltools/helper/figma/figma_client/models/domain/primitives/color.rb +44 -0
  23. data/admiraltools/helper/figma/figma_client/models/domain/primitives/component.rb +86 -0
  24. data/admiraltools/helper/figma/figma_client/models/domain/primitives/components_list.rb +29 -0
  25. data/admiraltools/helper/figma/figma_client/models/domain/primitives/font.rb +56 -0
  26. data/admiraltools/helper/figma/figma_client/models/domain/primitives/frame_info.rb +46 -0
  27. data/admiraltools/helper/figma/figma_client/models/domain/primitives/image_link.rb +33 -0
  28. data/admiraltools/helper/figma/figma_client/models/domain/primitives/style.rb +113 -0
  29. data/admiraltools/helper/figma/figma_client/models/domain/primitives/styles_group.rb +22 -0
  30. data/admiraltools/helper/figma/figma_client/models/domain/primitives/styles_list.rb +29 -0
  31. data/admiraltools/helper/figma/figma_client/models/models.rb +25 -0
  32. data/admiraltools/helper/figma/figma_image_downloader/bin/svg2vectordrawable.jar +0 -0
  33. data/admiraltools/helper/figma/figma_image_downloader/figma_image_downloader.rb +65 -0
  34. data/admiraltools/helper/figma/figma_image_downloader/generators/folder_generator.rb +47 -0
  35. data/admiraltools/helper/figma/figma_image_downloader/generators/folder_generator_raw.rb +32 -0
  36. data/admiraltools/helper/figma/figma_image_downloader/generators/folder_generator_res.rb +38 -0
  37. data/admiraltools/helper/figma/figma_image_downloader/generators/folder_generator_xcassets.rb +180 -0
  38. data/admiraltools/helper/figma/figma_image_downloader/generators/generators.rb +6 -0
  39. data/admiraltools/helper/figma/figma_image_downloader/helpers/image_name_formatter.rb +72 -0
  40. data/admiraltools/helper/figma/figma_image_downloader/helpers/progress_tasks_logger.rb +22 -0
  41. data/admiraltools/helper/figma/figma_image_downloader/helpers/scale_formatter.rb +96 -0
  42. data/admiraltools/helper/figma/figma_image_downloader/helpers/svg_to_vector_converter.rb +12 -0
  43. data/admiraltools/helper/figma/figma_image_downloader/models/download_image_params.rb +31 -0
  44. data/admiraltools/helper/figma/figma_image_downloader/models/image_name_components.rb +10 -0
  45. data/admiraltools/helper/figma/figma_image_downloader/models/image_ref.rb +12 -0
  46. data/admiraltools/helper/figma/figma_image_downloader/models/image_set_ref.rb +14 -0
  47. data/admiraltools/helper/figma/figma_image_downloader/models/models.rb +5 -0
  48. data/admiraltools/helper/figma/figma_template_generator/figma_template_generator.rb +22 -0
  49. data/admiraltools/helper/figma/figma_template_generator/models/styles_template.rb +34 -0
  50. data/admiraltools/helper/figma/helpers/file_folder.rb +30 -0
  51. data/admiraltools/helper/figma/helpers/hash_access.rb +18 -0
  52. data/admiraltools/helper/figma/helpers/string_filters.rb +63 -0
  53. data/admiraltools/helper/figma/helpers/string_format.rb +60 -0
  54. data/admiraltools/helper/system/system.rb +17 -0
  55. data/admiraltools/version.rb +7 -0
  56. data/admiraltools.rb +18 -0
  57. metadata +96 -0
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figma_frame_info'
4
+
5
+ class FigmaComponent
6
+ attr_accessor \
7
+ :key,
8
+ :file_key,
9
+ :node_id,
10
+ :name,
11
+ :description,
12
+ :containing_frame
13
+
14
+ def initialize(key:, file_key:, node_id:, name:, description:, containing_frame:)
15
+ @key = key
16
+ @file_key = file_key
17
+ @node_id = node_id
18
+ @name = name
19
+ @description = description
20
+ @containing_frame = containing_frame
21
+ end
22
+
23
+ def self.from_hash(hash)
24
+ return nil if hash.nil?
25
+
26
+ key = hash['key']
27
+ file_key = hash['file_key']
28
+ node_id = hash['node_id']
29
+ name = hash['name']
30
+ description = hash['description']
31
+ containing_frame_hash = hash['containing_frame']
32
+ containing_frame = containing_frame_hash.nil? ? nil : FigmaFrameInfo.from_hash(containing_frame_hash)
33
+
34
+ if !key.nil? && !file_key.nil? && !node_id.nil? && !name.nil?
35
+ return FigmaComponent.new(
36
+ key: key,
37
+ file_key: file_key,
38
+ node_id: node_id,
39
+ name: name,
40
+ description: description,
41
+ containing_frame: containing_frame
42
+ )
43
+ end
44
+
45
+ nil
46
+ end
47
+
48
+ def to_hash
49
+ hash = {}
50
+ hash['key'] = key
51
+ hash['file_key'] = file_key
52
+ hash['node_id'] = node_id
53
+ hash['name'] = name
54
+ hash['description'] = description
55
+ hash['containing_frame'] = containing_frame.to
56
+ hash
57
+ end
58
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figma_style'
4
+ require_relative 'figma_component'
5
+
6
+ class FigmaComponentsStylesMeta
7
+ attr_accessor :styles, :components
8
+
9
+ def initialize(styles:, components:)
10
+ @styles = styles
11
+ @components = components
12
+ end
13
+
14
+ def self.from_hash(hash)
15
+ styles_hash = hash['styles']
16
+ components_hash = hash['components']
17
+
18
+ styles = styles_hash.nil? ? nil : styles_hash.map { |s| FigmaStyle.from_hash(s) }
19
+ components = components_hash.nil? ? nil : components_hash.map { |c| FigmaComponent.from_hash(c) }
20
+
21
+ FigmaComponentsStylesMeta.new(styles: styles, components: components)
22
+ end
23
+
24
+ def to_hash
25
+ hash = {}
26
+ hash['styles'] = styles.map(&:to_hash) unless styles.nil?
27
+ hash['components'] = components.map(&:to_hash) unless components.nil?
28
+ hash
29
+ end
30
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FigmaFrameInfo
4
+ attr_accessor \
5
+ :node_id,
6
+ :name,
7
+ :background_color,
8
+ :page_id,
9
+ :page_name
10
+
11
+ def initialize(node_id:, name:, background_color:, page_id:, page_name:)
12
+ @node_id = node_id
13
+ @name = name
14
+ @background_color = background_color
15
+ @page_id = page_id
16
+ @page_name = page_name
17
+ end
18
+
19
+ def self.from_hash(hash)
20
+ return nil if hash.nil?
21
+
22
+ node_id = hash['nodeId']
23
+ name = hash['name']
24
+ background_color = hash['backgroundColor']
25
+ page_id = hash['pageId']
26
+ page_name = hash['pageName']
27
+
28
+ FigmaFrameInfo.new(
29
+ node_id: node_id,
30
+ name: name,
31
+ background_color: background_color,
32
+ page_id: page_id,
33
+ page_name: page_name
34
+ )
35
+ end
36
+
37
+ def to_hash
38
+ hash = {}
39
+ hash['nodeId'] = node_id
40
+ hash['name'] = name
41
+ hash['backgroundColor'] = background_color
42
+ hash['pageId'] = page_id
43
+ hash['pageName'] = page_name
44
+ hash
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figma_paint'
4
+ require_relative 'figma_type_style'
5
+
6
+ class FigmaNode
7
+ attr_accessor :id, :name, :type, :style, :fills
8
+
9
+ def initialize(id:, name:, type:, style:, fills:)
10
+ @id = id
11
+ @name = name
12
+ @type = type
13
+ @style = style
14
+ @fills = fills
15
+ end
16
+
17
+ def self.from_hash(hash)
18
+ return nil if hash.nil?
19
+
20
+ id = hash['id']
21
+ name = hash['name']
22
+ type = hash['type']
23
+ style_hash = hash['style']
24
+ style = style_hash.nil? ? nil : FigmaTypeStyle.from_hash(style_hash)
25
+ fills = (hash['fills'] || []).map { |f| FigmaPaint.from_hash(f) }.compact || []
26
+
27
+ if !id.nil? && !name.nil? && !type.nil?
28
+ return FigmaNode.new(id: id, name: name, type: type, style: style, fills: fills)
29
+ end
30
+
31
+ nil
32
+ end
33
+
34
+ def to_hash
35
+ hash = {}
36
+ hash['id'] = id
37
+ hash['name'] = name
38
+ hash['type'] = type
39
+ hash['style'] = style.to_hash unless style.nil?
40
+ hash['fills'] = (fills || []).map(&:to_hash)
41
+ hash
42
+ end
43
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'figma_color'
4
+
5
+ class FigmaPaint
6
+ attr_accessor :type, :color, :opacity
7
+
8
+ def initialize(type:, color:, opacity:)
9
+ @type = type
10
+ @color = color
11
+ @opacity = opacity
12
+ end
13
+
14
+ def self.from_hash(hash)
15
+ return nil if hash.nil?
16
+
17
+ type = hash['type']
18
+ color = FigmaColor.from_hash(hash['color'])
19
+ opacity = hash['opacity'] || 1.0
20
+
21
+ return FigmaPaint.new(type: type, color: color, opacity: opacity) if !type.nil? && !color.nil?
22
+
23
+ nil
24
+ end
25
+
26
+ def to_hash
27
+ hash = {}
28
+ hash['type'] = type
29
+ hash['color'] = color.to_hash unless color.nil?
30
+ hash
31
+ end
32
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ FIGMA_STYLE_TYPE_FILL = 'FILL'
4
+ FIGMA_STYLE_TYPE_TEXT = 'TEXT'
5
+
6
+ class FigmaStyle
7
+ attr_accessor \
8
+ :name,
9
+ :node_id,
10
+ :style_type,
11
+ :description
12
+
13
+ def initialize(
14
+ name:,
15
+ node_id:,
16
+ style_type:,
17
+ description:
18
+ )
19
+ @name = name
20
+ @node_id = node_id
21
+ @style_type = style_type
22
+ @description = description
23
+ end
24
+
25
+ def self.from_hash(hash)
26
+ return nil if hash.nil?
27
+
28
+ name = hash['name']
29
+ node_id = hash['node_id']
30
+ style_type = hash['style_type']
31
+ description = hash['description']
32
+
33
+ if !name.nil? && !node_id.nil? && style_type
34
+ return FigmaStyle.new(name: name, node_id: node_id, style_type: style_type, description: description)
35
+ end
36
+
37
+ nil
38
+ end
39
+
40
+ def to_hash
41
+ hash = {}
42
+ hash['name'] = name
43
+ hash['node_id'] = node_id
44
+ hash['style_type'] = style_type
45
+ hash['description'] = description
46
+ hash
47
+ end
48
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FigmaTypeStyle
4
+ attr_accessor \
5
+ :font_family,
6
+ :font_postscript_name,
7
+ :font_size,
8
+ :font_weight,
9
+ :letter_spacing
10
+
11
+ def initialize(
12
+ font_family:,
13
+ font_postscript_name:,
14
+ font_size:,
15
+ font_weight:,
16
+ letter_spacing:
17
+ )
18
+ @font_family = font_family
19
+ @font_postscript_name = font_postscript_name
20
+ @font_size = font_size
21
+ @font_weight = font_weight
22
+ @letter_spacing = letter_spacing
23
+ end
24
+
25
+ def self.from_hash(hash)
26
+ return nil if hash.nil?
27
+
28
+ font_family = hash['fontFamily']
29
+ font_postscript_name = hash['fontPostScriptName']
30
+ font_size = hash['fontSize']
31
+ font_weight = hash['fontWeight']
32
+ letter_spacing = hash['letterSpacing']
33
+
34
+ if !font_family.nil? && !font_size.nil? && !font_weight.nil? && !letter_spacing.nil?
35
+ return FigmaTypeStyle.new(
36
+ font_family: font_family,
37
+ font_postscript_name: font_postscript_name,
38
+ font_size: font_size,
39
+ font_weight: font_weight,
40
+ letter_spacing: letter_spacing
41
+ )
42
+ end
43
+
44
+ nil
45
+ end
46
+
47
+ def to_hash
48
+ hash = {}
49
+ hash['fontFamily'] = font_family
50
+ hash['fontPostscriptName'] = font_postscript_name
51
+ hash['fontSize'] = font_size
52
+ hash['fontWeight'] = font_weight
53
+ hash['letterSpacing'] = letter_spacing
54
+ hash
55
+ end
56
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../primitives/figma_components_styles_meta'
4
+
5
+ class FigmaComponentsStylesResult
6
+ attr_accessor :error, :status, :meta
7
+
8
+ def initialize(error:, status:, meta:)
9
+ @error = error
10
+ @status = status
11
+ @meta = meta
12
+ end
13
+
14
+ def self.from_hash(hash)
15
+ return nil if hash.nil?
16
+
17
+ error = hash['error']
18
+ status = hash['status']
19
+ meta_hash = hash['meta']
20
+ meta = meta_hash.nil? ? nil : FigmaComponentsStylesMeta.from_hash(meta_hash)
21
+
22
+ if !error.nil? && !status.nil? && !meta.nil?
23
+ return FigmaComponentsStylesResult.new(error: error, status: status, meta: meta)
24
+ end
25
+
26
+ nil
27
+ end
28
+
29
+ def to_hash
30
+ hash = {}
31
+ hash['error'] = error
32
+ hash['status'] = status
33
+ hash['meta'] = meta.to_hash unless meta.nil?
34
+ hash
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FigmaImagesResult
4
+ attr_accessor :error, :images
5
+
6
+ def initialize(error:, images:)
7
+ @error = error
8
+ @images = images || []
9
+ end
10
+
11
+ def self.from_hash(hash)
12
+ return nil if hash.nil?
13
+
14
+ error = hash['err']
15
+ images = hash['images']
16
+ FigmaImagesResult.new(error: error, images: images)
17
+ end
18
+
19
+ def to_hash
20
+ hash = {}
21
+ hash['err'] = error
22
+ hash['images'] = images
23
+ hash
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../primitives/figma_node'
4
+
5
+ class FigmaNodesResult
6
+ attr_accessor :name, :nodes
7
+
8
+ def initialize(name:, nodes:)
9
+ @name = name
10
+ @nodes = nodes
11
+ end
12
+
13
+ def self.from_hash(hash)
14
+ return nil if hash.nil?
15
+
16
+ name = hash['name']
17
+ nodes = FigmaNodesResult.parse_nodes(hash: hash['nodes'])
18
+
19
+ return FigmaNodesResult.new(name: name, nodes: nodes) if !name.nil? && !nodes.nil?
20
+
21
+ nil
22
+ end
23
+
24
+ def to_hash
25
+ hash = {}
26
+ hash['name'] = name
27
+ nodes_hash = (nodes || {})
28
+ nodes_result_hash = {}
29
+
30
+ nodes_hash.each do |k, v|
31
+ node = v['document'].to_hash
32
+ nodes_result_hash[k] = { 'document' => node } unless node.nil?
33
+ end
34
+
35
+ hash['nodes'] = nodes_result_hash
36
+ hash
37
+ end
38
+
39
+ def self.parse_nodes(hash:)
40
+ return nil if hash.nil?
41
+
42
+ result_hash = {}
43
+
44
+ hash.each do |k, v|
45
+ node_hash = v['document']
46
+ node = FigmaNode.from_hash(node_hash)
47
+ result_hash[k] = { 'document' => node } unless node.nil?
48
+ end
49
+
50
+ result_hash
51
+ end
52
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../models'
4
+
5
+ class FigmaToDomainConverter
6
+ def convert_figma_style(figma_style:)
7
+ return nil if figma_style.nil?
8
+
9
+ Style.new(
10
+ name: figma_style.name,
11
+ node_id: figma_style.node_id,
12
+ style_type: figma_style.style_type,
13
+ description: figma_style.description
14
+ )
15
+ end
16
+
17
+ def fulfill_styles(figma_nodes_result:, figma_styles_result:)
18
+ return [] if figma_nodes_result.nil? || figma_styles_result.nil?
19
+
20
+ styles = []
21
+ figma_styles = figma_styles_result&.meta&.styles || []
22
+ nodes = figma_nodes_result&.nodes || {}
23
+
24
+ figma_styles.each do |s|
25
+ style = convert_figma_style(figma_style: s)
26
+ node = nodes.dig(s.node_id, 'document')
27
+
28
+ case s.style_type
29
+ when FIGMA_STYLE_TYPE_FILL
30
+ fills = node&.fills
31
+ next if fills.nil?
32
+
33
+ figma_paint = fills[0]
34
+ next if figma_paint.nil?
35
+
36
+ style&.color = Color.new(
37
+ r: figma_paint.color.r,
38
+ g: figma_paint.color.g,
39
+ b: figma_paint.color.b,
40
+ a: figma_paint.opacity
41
+ )
42
+ styles.push(style)
43
+ when FIGMA_STYLE_TYPE_TEXT
44
+ type_style = node&.style
45
+ next if type_style.nil?
46
+
47
+ style&.font = Font.new(
48
+ font_family: type_style.font_family,
49
+ font_postscript_name: type_style.font_postscript_name,
50
+ font_size: type_style.font_size,
51
+ font_weight: type_style.font_weight,
52
+ letter_spacing: type_style.letter_spacing
53
+ )
54
+ styles.push(style)
55
+ else
56
+ next
57
+ end
58
+ end
59
+
60
+ styles
61
+ end
62
+
63
+ def fulfill_components(figma_components:, image_links_hash:, image_format:)
64
+ return [] if figma_components.nil? || image_links_hash.nil?
65
+
66
+ components = []
67
+ figma_components.each do |c|
68
+ component = Component.new(
69
+ key: c.key,
70
+ file_key: c.file_key,
71
+ node_id: c.node_id,
72
+ name: c.name,
73
+ description: c.description
74
+ )
75
+
76
+ component.containing_frame = FrameInfo.new(
77
+ node_id: c.containing_frame.node_id,
78
+ name: c.containing_frame.name,
79
+ background_color: c.containing_frame.background_color,
80
+ page_id: c.containing_frame.page_id,
81
+ page_name: c.containing_frame.page_name
82
+ )
83
+
84
+ image_links = []
85
+ image_links_hash.each do |key, link_hash|
86
+ link = link_hash[c.node_id]
87
+ if !link.nil? && !key.nil? && !image_format.nil?
88
+ image_link = ImageLink.new(link: link, scale: key, image_format: image_format)
89
+ image_links.push(image_link)
90
+ end
91
+ end
92
+ component.image_links = image_links
93
+ components.push(component)
94
+ end
95
+
96
+ components
97
+ end
98
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Color
4
+ attr_accessor :r, :g, :b, :a
5
+
6
+ def hex
7
+ format('#%02x%02x%02x', *[r, g, b].map { |v| v.to_f * 255 }).upcase
8
+ end
9
+
10
+ def hex_with_alpha
11
+ format('#%02x%02x%02x%02x', *[a, r, g, b].map { |v| v.to_f * 255 }).upcase
12
+ end
13
+
14
+ def initialize(r:, g:, b:, a:)
15
+ @r = r
16
+ @g = g
17
+ @b = b
18
+ @a = a
19
+ end
20
+
21
+ def self.from_hash(hash)
22
+ return nil if hash.nil?
23
+
24
+ r = hash['r']
25
+ g = hash['g']
26
+ b = hash['b']
27
+ a = hash['a']
28
+
29
+ return Color.new(r: r, g: g, b: b, a: a) if !r.nil? && !g.nil? && !b.nil? && !a.nil?
30
+
31
+ nil
32
+ end
33
+
34
+ def to_hash
35
+ hash = {}
36
+ hash['r'] = r
37
+ hash['g'] = g
38
+ hash['b'] = b
39
+ hash['a'] = a
40
+ hash['hex'] = hex
41
+ hash['hex_with_alpha'] = hex_with_alpha
42
+ hash
43
+ end
44
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'image_link'
4
+ require_relative 'frame_info'
5
+
6
+ class Component
7
+ attr_accessor \
8
+ :key,
9
+ :file_key,
10
+ :node_id,
11
+ :name,
12
+ :description,
13
+ :containing_frame,
14
+ :image_links
15
+
16
+ def single_scale?
17
+ links = image_links || []
18
+ return false if links.length > 1
19
+
20
+ link = links[0]
21
+ return false if link.nil?
22
+
23
+ image_format = link&.image_format
24
+ return false if image_format.nil?
25
+
26
+ scale = link.scale
27
+ image_format = image_format.downcase
28
+ scale == 1.0 && %w[svg pdf].include?(image_format)
29
+ end
30
+
31
+ def description_params
32
+ JSON.parse(description)
33
+ rescue StandardError
34
+ nil
35
+ end
36
+
37
+ def initialize(key:, file_key:, node_id:, name:, description:, containing_frame: nil, image_links: nil)
38
+ @key = key
39
+ @file_key = file_key
40
+ @node_id = node_id
41
+ @name = name
42
+ @description = description
43
+ @containing_frame = containing_frame
44
+ @image_links = image_links
45
+ end
46
+
47
+ def self.from_hash(hash)
48
+ return nil if hash.nil?
49
+
50
+ key = hash['key']
51
+ file_key = hash['file_key']
52
+ node_id = hash['node_id']
53
+ name = hash['name']
54
+ description = hash['description']
55
+ images_array = hash['image_links']
56
+ image_links = images_array&.map { |i| ImageLink.from_hash(i) }
57
+ containing_frame = FrameInfo.from_hash(hash['containing_frame'])
58
+
59
+ if !key.nil? && !file_key.nil? && !node_id.nil? && !name.nil?
60
+ return Component.new(
61
+ key: key,
62
+ file_key: file_key,
63
+ node_id: node_id,
64
+ name: name,
65
+ description: description,
66
+ containing_frame: containing_frame,
67
+ image_links: image_links
68
+ )
69
+ end
70
+
71
+ nil
72
+ end
73
+
74
+ def to_hash
75
+ hash = {}
76
+ hash['key'] = key
77
+ hash['file_key'] = file_key
78
+ hash['node_id'] = node_id
79
+ hash['name'] = name
80
+ hash['description'] = description
81
+ hash['image_links'] = image_links&.map { |i| i.to_hash } unless image_links.nil?
82
+ hash['description_params'] = description_params unless description_params.nil?
83
+ hash['containing_frame'] = containing_frame&.to_hash
84
+ hash
85
+ end
86
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'component'
5
+
6
+ class ComponentsList
7
+ attr_accessor :components
8
+
9
+ def initialize(components:)
10
+ @components = components
11
+ end
12
+
13
+ def self.from_hash(hash)
14
+ hash.map { |s| Component.from_hash(s) }
15
+ end
16
+
17
+ def to_hash
18
+ components.map(&:to_hash)
19
+ end
20
+
21
+ def self.from_json(json)
22
+ components = (JSON.parse(json) || []).map { |s| Component.from_hash(s) }
23
+ ComponentsList.new(components: components)
24
+ end
25
+
26
+ def to_json(*_args)
27
+ components.map(&:to_hash).to_json
28
+ end
29
+ end