shopify-cli 1.8.0 → 1.9.0

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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +15 -2
  3. data/CHANGELOG.md +4 -1
  4. data/Gemfile.lock +3 -3
  5. data/dev.yml +3 -0
  6. data/lib/graphql/extension_create.graphql +17 -2
  7. data/lib/project_types/extension/cli.rb +2 -0
  8. data/lib/project_types/extension/commands/extension_command.rb +4 -4
  9. data/lib/project_types/extension/commands/push.rb +2 -2
  10. data/lib/project_types/extension/commands/register.rb +4 -3
  11. data/lib/project_types/extension/commands/serve.rb +1 -35
  12. data/lib/project_types/extension/extension_project.rb +15 -4
  13. data/lib/project_types/extension/extension_project_keys.rb +2 -1
  14. data/lib/project_types/extension/features/argo.rb +6 -0
  15. data/lib/project_types/extension/features/argo_renderer_package.rb +32 -0
  16. data/lib/project_types/extension/features/argo_serve.rb +69 -0
  17. data/lib/project_types/extension/messages/message_loading.rb +3 -1
  18. data/lib/project_types/extension/models/registration.rb +1 -0
  19. data/lib/project_types/extension/models/specification.rb +2 -0
  20. data/lib/project_types/extension/models/specification_handlers/default.rb +8 -0
  21. data/lib/project_types/extension/tasks/configure_features.rb +2 -0
  22. data/lib/project_types/extension/tasks/converters/registration_converter.rb +2 -0
  23. data/lib/project_types/node/commands/generate.rb +0 -22
  24. data/lib/project_types/script/cli.rb +2 -8
  25. data/lib/project_types/script/commands/create.rb +0 -7
  26. data/lib/project_types/script/commands/push.rb +2 -2
  27. data/lib/project_types/script/config/extension_points.yml +2 -0
  28. data/lib/project_types/script/errors.rb +0 -19
  29. data/lib/project_types/script/forms/create.rb +3 -14
  30. data/lib/project_types/script/graphql/app_script_update_or_create.graphql +0 -3
  31. data/lib/project_types/script/graphql/script_service_proxy.graphql +1 -2
  32. data/lib/project_types/script/layers/application/build_script.rb +1 -2
  33. data/lib/project_types/script/layers/application/create_script.rb +30 -51
  34. data/lib/project_types/script/layers/application/extension_points.rb +3 -2
  35. data/lib/project_types/script/layers/application/push_script.rb +2 -4
  36. data/lib/project_types/script/layers/domain/extension_point.rb +56 -46
  37. data/lib/project_types/script/layers/domain/metadata.rb +18 -25
  38. data/lib/project_types/script/layers/domain/push_package.rb +0 -4
  39. data/lib/project_types/script/layers/domain/script_project.rb +34 -0
  40. data/lib/project_types/script/layers/infrastructure/assemblyscript_project_creator.rb +6 -2
  41. data/lib/project_types/script/layers/infrastructure/assemblyscript_task_runner.rb +4 -4
  42. data/lib/project_types/script/layers/infrastructure/errors.rb +12 -10
  43. data/lib/project_types/script/layers/infrastructure/push_package_repository.rb +10 -12
  44. data/lib/project_types/script/layers/infrastructure/rust_task_runner.rb +1 -1
  45. data/lib/project_types/script/layers/infrastructure/script_project_repository.rb +145 -0
  46. data/lib/project_types/script/layers/infrastructure/script_service.rb +9 -72
  47. data/lib/project_types/script/messages/messages.rb +0 -47
  48. data/lib/project_types/script/ui/error_handler.rb +7 -24
  49. data/lib/shopify-cli/context.rb +28 -0
  50. data/lib/shopify-cli/version.rb +1 -1
  51. metadata +6 -10
  52. data/lib/project_types/script/commands/disable.rb +0 -25
  53. data/lib/project_types/script/commands/enable.rb +0 -80
  54. data/lib/project_types/script/graphql/shop_script_delete.graphql +0 -14
  55. data/lib/project_types/script/graphql/shop_script_update_or_create.graphql +0 -28
  56. data/lib/project_types/script/layers/application/disable_script.rb +0 -21
  57. data/lib/project_types/script/layers/application/enable_script.rb +0 -23
  58. data/lib/project_types/script/layers/infrastructure/config_ui_repository.rb +0 -46
  59. data/lib/project_types/script/script_project.rb +0 -64
@@ -6,19 +6,17 @@ module Script
6
6
  class PushScript
7
7
  class << self
8
8
  def call(ctx:, force:)
9
- script_project = ScriptProject.current
9
+ script_project = Infrastructure::ScriptProjectRepository.new(ctx: ctx).get
10
10
  task_runner = Infrastructure::TaskRunner.for(ctx, script_project.language, script_project.script_name)
11
- config_ui = Infrastructure::ConfigUiRepository.new(ctx: ctx).get_config_ui(script_project.config_ui_file)
12
11
 
13
12
  ProjectDependencies.install(ctx: ctx, task_runner: task_runner)
14
- BuildScript.call(ctx: ctx, task_runner: task_runner, script_project: script_project, config_ui: config_ui)
13
+ BuildScript.call(ctx: ctx, task_runner: task_runner, script_project: script_project)
15
14
 
16
15
  UI::PrintingSpinner.spin(ctx, ctx.message("script.application.pushing")) do |p_ctx, spinner|
17
16
  package = Infrastructure::PushPackageRepository.new(ctx: p_ctx).get_push_package(
18
17
  script_project: script_project,
19
18
  compiled_type: task_runner.compiled_type,
20
19
  metadata: task_runner.metadata,
21
- config_ui: config_ui,
22
20
  )
23
21
  package.push(Infrastructure::ScriptService.new(ctx: p_ctx), script_project.api_key, force)
24
22
  spinner.update_title(p_ctx.message("script.application.pushed"))
@@ -4,15 +4,20 @@ module Script
4
4
  module Layers
5
5
  module Domain
6
6
  class ExtensionPoint
7
- attr_reader :type, :deprecated, :sdks, :domain
7
+ attr_reader :type, :beta, :deprecated, :sdks, :domain
8
8
 
9
9
  def initialize(type, config)
10
10
  @type = type
11
+ @beta = config["beta"] || false
11
12
  @deprecated = config["deprecated"] || false
12
13
  @domain = config["domain"] || nil
13
14
  @sdks = ExtensionPointSDKs.new(config)
14
15
  end
15
16
 
17
+ def beta?
18
+ @beta
19
+ end
20
+
16
21
  def deprecated?
17
22
  @deprecated
18
23
  end
@@ -20,68 +25,73 @@ module Script
20
25
  def dasherize_type
21
26
  @type.gsub("_", "-")
22
27
  end
23
- end
24
28
 
25
- class ExtensionPointSDKs
26
- def initialize(config)
27
- @config = config
28
- end
29
+ class ExtensionPointSDKs
30
+ def initialize(config)
31
+ @config = config
32
+ end
29
33
 
30
- def all
31
- [assemblyscript, rust].compact
32
- end
34
+ def all
35
+ [assemblyscript, rust].compact
36
+ end
33
37
 
34
- def assemblyscript
35
- @assemblyscript ||= new_sdk(ExtensionPointAssemblyScriptSDK)
36
- end
38
+ def assemblyscript
39
+ @assemblyscript ||= new_sdk(ExtensionPointAssemblyScriptSDK)
40
+ end
37
41
 
38
- def rust
39
- @rust ||= new_sdk(ExtensionPointRustSDK)
40
- end
42
+ def rust
43
+ @rust ||= new_sdk(ExtensionPointRustSDK)
44
+ end
41
45
 
42
- private
46
+ private
43
47
 
44
- def new_sdk(klass)
45
- config = @config[klass.language]
46
- return nil if config.nil?
47
- klass.new(config)
48
+ def new_sdk(klass)
49
+ config = @config[klass.language]
50
+ return nil if config.nil?
51
+ klass.new(config)
52
+ end
48
53
  end
49
- end
50
54
 
51
- class ExtensionPointSDK
52
- attr_reader :beta, :package
55
+ class ExtensionPointSDK
56
+ attr_reader :version, :beta, :package
53
57
 
54
- def initialize(config)
55
- @beta = config["beta"] || false
56
- @package = config["package"]
57
- end
58
+ def initialize(config)
59
+ @beta = config["beta"] || false
60
+ @package = config["package"]
61
+ @version = config["package-version"]
62
+ end
58
63
 
59
- def beta?
60
- @beta
61
- end
64
+ def beta?
65
+ @beta
66
+ end
67
+
68
+ def versioned?
69
+ @version
70
+ end
62
71
 
63
- def self.language
64
- raise NotImplementedError
72
+ def self.language
73
+ raise NotImplementedError
74
+ end
65
75
  end
66
- end
67
76
 
68
- class ExtensionPointAssemblyScriptSDK < ExtensionPointSDK
69
- attr_reader :sdk_version, :toolchain_version
77
+ class ExtensionPointAssemblyScriptSDK < ExtensionPointSDK
78
+ attr_reader :sdk_version, :toolchain_version
70
79
 
71
- def initialize(config)
72
- super
73
- @sdk_version = config["sdk-version"]
74
- @toolchain_version = config["toolchain-version"]
75
- end
80
+ def initialize(config)
81
+ super
82
+ @sdk_version = config["sdk-version"]
83
+ @toolchain_version = config["toolchain-version"]
84
+ end
76
85
 
77
- def self.language
78
- "assemblyscript"
86
+ def self.language
87
+ "assemblyscript"
88
+ end
79
89
  end
80
- end
81
90
 
82
- class ExtensionPointRustSDK < ExtensionPointSDK
83
- def self.language
84
- "rust"
91
+ class ExtensionPointRustSDK < ExtensionPointSDK
92
+ def self.language
93
+ "rust"
94
+ end
85
95
  end
86
96
  end
87
97
  end
@@ -14,39 +14,32 @@ module Script
14
14
 
15
15
  class << self
16
16
  def create_from_json(ctx, metadata_json)
17
+ err_tag = nil
17
18
  metadata_hash = JSON.parse(metadata_json)
18
- schema_versions = metadata_hash["schemaVersions"]
19
- if schema_versions.nil?
20
- err_msg = "script.error.metadata_schema_versions_missing"
21
- raise ::Script::Layers::Domain::Errors::MetadataValidationError, ctx.message(err_msg)
22
- end
23
- # Scripts may be attached to more than one EP in the future but not right now
24
- unless schema_versions.count == 1
25
- err_msg = "script.error.metadata_schema_versions_single_key"
26
- raise ::Script::Layers::Domain::Errors::MetadataValidationError, ctx.message(err_msg)
27
- end
28
19
 
29
- _, version = schema_versions.first
20
+ use_msgpack = !!metadata_hash.dig("flags", "use_msgpack")
21
+ schema_versions = metadata_hash["schemaVersions"] || {}
22
+
23
+ version = schema_versions.values.first || {}
30
24
  schema_major_version = version["major"]
31
25
  schema_minor_version = version["minor"]
32
- if schema_major_version.nil?
33
- err_msg = "script.error.metadata_schema_versions_missing_major"
34
- raise ::Script::Layers::Domain::Errors::MetadataValidationError, ctx.message(err_msg)
35
- end
36
26
 
37
- if schema_minor_version.nil?
38
- err_msg = "script.error.metadata_schema_versions_missing_minor"
39
- raise ::Script::Layers::Domain::Errors::MetadataValidationError, ctx.message(err_msg)
27
+ if schema_versions.empty?
28
+ err_tag = "script.error.metadata_schema_versions_missing"
29
+ elsif schema_versions.count != 1
30
+ # Scripts may be attached to more than one EP in the future but not right now
31
+ err_tag = "script.error.metadata_schema_versions_single_key"
32
+ elsif schema_major_version.nil?
33
+ err_tag = "script.error.metadata_schema_versions_missing_major"
34
+ elsif schema_minor_version.nil?
35
+ err_tag = "script.error.metadata_schema_versions_missing_minor"
40
36
  end
41
37
 
42
- use_msgpack = !!metadata_hash.dig("flags", "use_msgpack")
43
-
44
38
  Metadata.new(schema_major_version, schema_minor_version, use_msgpack)
45
- rescue ::Script::Layers::Domain::Errors::MetadataValidationError
46
- raise
47
- rescue
48
- err_msg = "script.error.metadata_validation_cause"
49
- raise ::Script::Layers::Domain::Errors::MetadataValidationError, ctx.message(err_msg)
39
+ rescue JSON::ParserError
40
+ err_tag = "script.error.metadata_validation_cause"
41
+ ensure
42
+ raise Errors::MetadataValidationError, ctx.message(err_tag) if err_tag
50
43
  end
51
44
  end
52
45
  end
@@ -7,7 +7,6 @@ module Script
7
7
  attr_reader :id,
8
8
  :extension_point_type,
9
9
  :script_name,
10
- :description,
11
10
  :config_ui,
12
11
  :script_content,
13
12
  :compiled_type,
@@ -17,7 +16,6 @@ module Script
17
16
  id:,
18
17
  extension_point_type:,
19
18
  script_name:,
20
- description:,
21
19
  script_content:,
22
20
  compiled_type:,
23
21
  metadata:,
@@ -26,7 +24,6 @@ module Script
26
24
  @id = id
27
25
  @extension_point_type = extension_point_type
28
26
  @script_name = script_name
29
- @description = description
30
27
  @script_content = script_content
31
28
  @compiled_type = compiled_type
32
29
  @metadata = metadata
@@ -37,7 +34,6 @@ module Script
37
34
  script_service.push(
38
35
  extension_point_type: @extension_point_type,
39
36
  script_name: @script_name,
40
- description: @description,
41
37
  script_content: @script_content,
42
38
  compiled_type: @compiled_type,
43
39
  api_key: api_key,
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Domain
6
+ class ScriptProject
7
+ include SmartProperties
8
+
9
+ property! :id, accepts: String
10
+ property :env, accepts: ShopifyCli::Resources::EnvFile
11
+
12
+ property! :extension_point_type, accepts: String
13
+ property! :script_name, accepts: String
14
+ property! :language, accepts: String
15
+
16
+ property :config_ui, accepts: ConfigUi
17
+
18
+ def initialize(*)
19
+ super
20
+
21
+ ShopifyCli::Core::Monorail.metadata = {
22
+ "script_name" => script_name,
23
+ "extension_point_type" => extension_point_type,
24
+ "language" => language,
25
+ }
26
+ end
27
+
28
+ def api_key
29
+ env[:api_key]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -38,9 +38,13 @@ module Script
38
38
  end
39
39
 
40
40
  def extension_point_version
41
+ if extension_point.sdks.assemblyscript.versioned?
42
+ return extension_point.sdks.assemblyscript.version
43
+ end
44
+
41
45
  out, status = ctx.capture2e("npm show #{extension_point.sdks.assemblyscript.package} version --json")
42
46
  raise Domain::Errors::ServiceFailureError, out unless status.success?
43
- JSON.parse(out)
47
+ "^#{JSON.parse(out)}"
44
48
  end
45
49
 
46
50
  def write_package_json
@@ -51,7 +55,7 @@ module Script
51
55
  "devDependencies": {
52
56
  "@shopify/scripts-sdk-as": "#{extension_point.sdks.assemblyscript.sdk_version}",
53
57
  "@shopify/scripts-toolchain-as": "#{extension_point.sdks.assemblyscript.toolchain_version}",
54
- "#{extension_point.sdks.assemblyscript.package}": "^#{extension_point_version}",
58
+ "#{extension_point.sdks.assemblyscript.package}": "#{extension_point_version}",
55
59
  "@as-pect/cli": "^6.0.0",
56
60
  "assemblyscript": "^0.18.13"
57
61
  },
@@ -81,11 +81,11 @@ module Script
81
81
  end
82
82
 
83
83
  def bytecode
84
- blob = format(BYTECODE_FILE, name: script_name)
85
- raise Errors::WebAssemblyBinaryNotFoundError unless @ctx.file_exist?(blob)
84
+ filename = format(BYTECODE_FILE, name: script_name)
85
+ raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(filename)
86
86
 
87
- contents = File.read(blob)
88
- @ctx.rm(blob)
87
+ contents = ctx.binread(filename)
88
+ ctx.rm(filename)
89
89
 
90
90
  contents
91
91
  end
@@ -5,8 +5,6 @@ module Script
5
5
  module Infrastructure
6
6
  module Errors
7
7
  class AppNotInstalledError < ScriptProjectError; end
8
- class AppScriptNotPushedError < ScriptProjectError; end
9
- class AppScriptUndefinedError < ScriptProjectError; end
10
8
  class BuildError < ScriptProjectError; end
11
9
  class ConfigUiSyntaxError < ScriptProjectError; end
12
10
 
@@ -29,8 +27,19 @@ module Script
29
27
  end
30
28
 
31
29
  class DependencyInstallError < ScriptProjectError; end
30
+ class DeprecatedEPError < ScriptProjectError; end
32
31
  class EmptyResponseError < ScriptProjectError; end
33
32
  class ForbiddenError < ScriptProjectError; end
33
+ class InvalidContextError < ScriptProjectError; end
34
+
35
+ class InvalidLanguageError < ScriptProjectError
36
+ attr_reader :language, :extension_point_type
37
+ def initialize(language, extension_point_type)
38
+ super()
39
+ @language = language
40
+ @extension_point_type = extension_point_type
41
+ end
42
+ end
34
43
 
35
44
  class GraphqlError < ScriptProjectError
36
45
  attr_reader :errors
@@ -50,15 +59,8 @@ module Script
50
59
  end
51
60
  end
52
61
 
53
- class ScriptServiceUserError < ScriptProjectError
54
- def initialize(query_name, errors)
55
- super("Failed performing #{query_name}. Errors: #{errors}.")
56
- end
57
- end
58
-
62
+ class ScriptProjectAlreadyExistsError < ScriptProjectError; end
59
63
  class ShopAuthenticationError < ScriptProjectError; end
60
- class ShopScriptConflictError < ScriptProjectError; end
61
- class ShopScriptUndefinedError < ScriptProjectError; end
62
64
  class TaskRunnerNotFoundError < ScriptProjectError; end
63
65
  class BuildScriptNotFoundError < ScriptProjectError; end
64
66
  class InvalidBuildScriptError < ScriptProjectError; end
@@ -7,37 +7,35 @@ module Script
7
7
  include SmartProperties
8
8
  property! :ctx, accepts: ShopifyCli::Context
9
9
 
10
- def create_push_package(script_project:, script_content:, compiled_type:, metadata:, config_ui:)
11
- build_file_path = file_path(script_project.script_name, compiled_type)
10
+ def create_push_package(script_project:, script_content:, compiled_type:, metadata:)
11
+ build_file_path = file_path(script_project.id, script_project.script_name, compiled_type)
12
12
  write_to_path(build_file_path, script_content)
13
13
 
14
14
  Domain::PushPackage.new(
15
15
  id: build_file_path,
16
16
  extension_point_type: script_project.extension_point_type,
17
17
  script_name: script_project.script_name,
18
- description: script_project.description,
19
18
  script_content: script_content,
20
19
  compiled_type: compiled_type,
21
20
  metadata: metadata,
22
- config_ui: config_ui,
21
+ config_ui: script_project.config_ui,
23
22
  )
24
23
  end
25
24
 
26
- def get_push_package(script_project:, compiled_type:, metadata:, config_ui:)
27
- build_file_path = file_path(script_project.script_name, compiled_type)
25
+ def get_push_package(script_project:, compiled_type:, metadata:)
26
+ build_file_path = file_path(script_project.id, script_project.script_name, compiled_type)
28
27
  raise Domain::PushPackageNotFoundError unless ctx.file_exist?(build_file_path)
29
28
 
30
- script_content = File.read(build_file_path)
29
+ script_content = ctx.binread(build_file_path)
31
30
 
32
31
  Domain::PushPackage.new(
33
32
  id: build_file_path,
34
33
  extension_point_type: script_project.extension_point_type,
35
34
  script_name: script_project.script_name,
36
- description: script_project.description,
37
35
  script_content: script_content,
38
36
  compiled_type: compiled_type,
39
37
  metadata: metadata,
40
- config_ui: config_ui,
38
+ config_ui: script_project.config_ui,
41
39
  )
42
40
  end
43
41
 
@@ -45,11 +43,11 @@ module Script
45
43
 
46
44
  def write_to_path(path, content)
47
45
  ctx.mkdir_p(File.dirname(path))
48
- ctx.write(path, content)
46
+ ctx.binwrite(path, content)
49
47
  end
50
48
 
51
- def file_path(script_name, compiled_type)
52
- "#{ScriptProject.current.directory}/build/#{script_name}.#{compiled_type}"
49
+ def file_path(path_to_script, script_name, compiled_type)
50
+ "#{path_to_script}/build/#{script_name}.#{compiled_type}"
53
51
  end
54
52
  end
55
53
  end
@@ -51,7 +51,7 @@ module Script
51
51
  binary_path = "target/#{BUILD_TARGET}/release/#{binary_name}"
52
52
  raise Errors::WebAssemblyBinaryNotFoundError unless ctx.file_exist?(binary_path)
53
53
 
54
- File.read(binary_path)
54
+ ctx.binread(binary_path)
55
55
  end
56
56
  end
57
57
  end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Script
4
+ module Layers
5
+ module Infrastructure
6
+ class ScriptProjectRepository
7
+ include SmartProperties
8
+ property! :ctx, accepts: ShopifyCli::Context
9
+
10
+ DEFAULT_CONFIG_UI_FILENAME = "config-ui.yml"
11
+
12
+ def create(script_name:, extension_point_type:, language:, no_config_ui:)
13
+ validate_metadata!(extension_point_type, language)
14
+
15
+ optional_identifiers = {}
16
+ config_ui_file = nil
17
+
18
+ unless no_config_ui
19
+ optional_identifiers.merge!(config_ui_file: DEFAULT_CONFIG_UI_FILENAME)
20
+ config_ui_file = ConfigUiRepository
21
+ .new(ctx: ctx)
22
+ .create(DEFAULT_CONFIG_UI_FILENAME, default_config_ui_content(script_name))
23
+ end
24
+
25
+ ShopifyCli::Project.write(
26
+ ctx,
27
+ project_type: :script,
28
+ organization_id: nil,
29
+ extension_point_type: extension_point_type,
30
+ script_name: script_name,
31
+ language: language,
32
+ **optional_identifiers
33
+ )
34
+
35
+ Domain::ScriptProject.new(
36
+ id: ctx.root,
37
+ env: project.env,
38
+ script_name: script_name,
39
+ extension_point_type: extension_point_type,
40
+ language: language,
41
+ config_ui: config_ui_file
42
+ )
43
+ end
44
+
45
+ def get
46
+ extension_point_type = project_config_value!("extension_point_type")
47
+ script_name = project_config_value!("script_name")
48
+ config_ui_file = project_config_value("config_ui_file")
49
+ language = project_config_value("language")&.downcase || default_language
50
+
51
+ validate_metadata!(extension_point_type, language)
52
+
53
+ config_ui = ConfigUiRepository.new(ctx: ctx).get(config_ui_file)
54
+
55
+ Domain::ScriptProject.new(
56
+ id: project.directory,
57
+ env: project.env,
58
+ script_name: script_name,
59
+ extension_point_type: extension_point_type,
60
+ language: language,
61
+ config_ui: config_ui
62
+ )
63
+ end
64
+
65
+ private
66
+
67
+ def project_config_value(key)
68
+ return nil unless project.config.key?(key)
69
+ project.config[key]
70
+ end
71
+
72
+ def project_config_value!(key)
73
+ raise Errors::InvalidContextError, key unless project.config.key?(key)
74
+ project.config[key]
75
+ end
76
+
77
+ def project
78
+ ShopifyCli::Project.current
79
+ end
80
+
81
+ def default_config_ui_content(title)
82
+ require "yaml" # takes 20ms, so deferred as late as possible.
83
+ YAML.dump({
84
+ "version" => 1,
85
+ "inputMode" => "single",
86
+ "title" => title,
87
+ "description" => "",
88
+ "fields" => [],
89
+ })
90
+ end
91
+
92
+ def default_language
93
+ Domain::ExtensionPoint::ExtensionPointAssemblyScriptSDK.language
94
+ end
95
+
96
+ def validate_metadata!(extension_point_type, language)
97
+ if Application::ExtensionPoints.deprecated_types.include?(extension_point_type)
98
+ raise Errors::DeprecatedEPError, extension_point_type
99
+ elsif !Application::ExtensionPoints.supported_language?(type: extension_point_type, language: language)
100
+ raise Errors::InvalidLanguageError.new(language, extension_point_type)
101
+ end
102
+ end
103
+
104
+ class ConfigUiRepository
105
+ include SmartProperties
106
+ property! :ctx, accepts: ShopifyCli::Context
107
+
108
+ def create(filename, content)
109
+ File.write(filename, content)
110
+
111
+ Domain::ConfigUi.new(
112
+ filename: filename,
113
+ content: content,
114
+ )
115
+ end
116
+
117
+ def get(filename)
118
+ return nil unless filename
119
+
120
+ path = File.join(ctx.root, filename)
121
+ raise Domain::Errors::MissingSpecifiedConfigUiDefinitionError, filename unless File.exist?(path)
122
+
123
+ content = File.read(path)
124
+ raise Domain::Errors::InvalidConfigUiDefinitionError, filename unless valid_config_ui?(content)
125
+
126
+ Domain::ConfigUi.new(
127
+ filename: filename,
128
+ content: content,
129
+ )
130
+ end
131
+
132
+ private
133
+
134
+ def valid_config_ui?(raw_yaml)
135
+ require "yaml" # takes 20ms, so deferred as late as possible.
136
+ YAML.safe_load(raw_yaml)
137
+ true
138
+ rescue Psych::SyntaxError
139
+ false
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end