igniter-extensions 0.5.2
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.
- checksums.yaml +7 -0
- data/README.md +381 -0
- data/lib/igniter/extensions/contracts/aggregate_pack.rb +103 -0
- data/lib/igniter/extensions/contracts/audit/builder.rb +132 -0
- data/lib/igniter/extensions/contracts/audit/event.rb +34 -0
- data/lib/igniter/extensions/contracts/audit/snapshot.rb +44 -0
- data/lib/igniter/extensions/contracts/audit_pack.rb +60 -0
- data/lib/igniter/extensions/contracts/branch_pack.rb +199 -0
- data/lib/igniter/extensions/contracts/capabilities/declaration.rb +31 -0
- data/lib/igniter/extensions/contracts/capabilities/error.rb +35 -0
- data/lib/igniter/extensions/contracts/capabilities/policy.rb +20 -0
- data/lib/igniter/extensions/contracts/capabilities/report.rb +47 -0
- data/lib/igniter/extensions/contracts/capabilities/violation.rb +30 -0
- data/lib/igniter/extensions/contracts/capabilities_pack.rb +146 -0
- data/lib/igniter/extensions/contracts/collection_pack.rb +212 -0
- data/lib/igniter/extensions/contracts/commerce_pack.rb +91 -0
- data/lib/igniter/extensions/contracts/compose_pack.rb +213 -0
- data/lib/igniter/extensions/contracts/content_addressing/cache.rb +59 -0
- data/lib/igniter/extensions/contracts/content_addressing/content_key.rb +63 -0
- data/lib/igniter/extensions/contracts/content_addressing/declaration.rb +47 -0
- data/lib/igniter/extensions/contracts/content_addressing_pack.rb +90 -0
- data/lib/igniter/extensions/contracts/creator/profile.rb +196 -0
- data/lib/igniter/extensions/contracts/creator/report.rb +85 -0
- data/lib/igniter/extensions/contracts/creator/scaffold.rb +461 -0
- data/lib/igniter/extensions/contracts/creator/scope.rb +79 -0
- data/lib/igniter/extensions/contracts/creator/wizard.rb +269 -0
- data/lib/igniter/extensions/contracts/creator/workflow.rb +189 -0
- data/lib/igniter/extensions/contracts/creator/workflow_step.rb +51 -0
- data/lib/igniter/extensions/contracts/creator/write_result.rb +48 -0
- data/lib/igniter/extensions/contracts/creator/write_step.rb +63 -0
- data/lib/igniter/extensions/contracts/creator/writer.rb +131 -0
- data/lib/igniter/extensions/contracts/creator_pack.rb +128 -0
- data/lib/igniter/extensions/contracts/dataflow/aggregate_operators.rb +119 -0
- data/lib/igniter/extensions/contracts/dataflow/aggregate_state.rb +60 -0
- data/lib/igniter/extensions/contracts/dataflow/builder.rb +66 -0
- data/lib/igniter/extensions/contracts/dataflow/collection_result.rb +70 -0
- data/lib/igniter/extensions/contracts/dataflow/diff.rb +37 -0
- data/lib/igniter/extensions/contracts/dataflow/item_result.rb +44 -0
- data/lib/igniter/extensions/contracts/dataflow/result.rb +58 -0
- data/lib/igniter/extensions/contracts/dataflow/session.rb +173 -0
- data/lib/igniter/extensions/contracts/dataflow/window_filter.rb +49 -0
- data/lib/igniter/extensions/contracts/dataflow_pack.rb +66 -0
- data/lib/igniter/extensions/contracts/debug/pack_audit.rb +181 -0
- data/lib/igniter/extensions/contracts/debug/pack_snapshot.rb +46 -0
- data/lib/igniter/extensions/contracts/debug/profile_snapshot.rb +50 -0
- data/lib/igniter/extensions/contracts/debug/report.rb +50 -0
- data/lib/igniter/extensions/contracts/debug_pack.rb +115 -0
- data/lib/igniter/extensions/contracts/differential/divergence.rb +37 -0
- data/lib/igniter/extensions/contracts/differential/formatter.rb +85 -0
- data/lib/igniter/extensions/contracts/differential/report.rb +83 -0
- data/lib/igniter/extensions/contracts/differential/runner.rb +136 -0
- data/lib/igniter/extensions/contracts/differential_pack.rb +61 -0
- data/lib/igniter/extensions/contracts/execution_report_pack.rb +38 -0
- data/lib/igniter/extensions/contracts/incremental/formatter.rb +60 -0
- data/lib/igniter/extensions/contracts/incremental/node_state.rb +30 -0
- data/lib/igniter/extensions/contracts/incremental/result.rb +65 -0
- data/lib/igniter/extensions/contracts/incremental/session.rb +146 -0
- data/lib/igniter/extensions/contracts/incremental_pack.rb +40 -0
- data/lib/igniter/extensions/contracts/invariants/builder.rb +27 -0
- data/lib/igniter/extensions/contracts/invariants/cases_report.rb +47 -0
- data/lib/igniter/extensions/contracts/invariants/error.rb +34 -0
- data/lib/igniter/extensions/contracts/invariants/invariant.rb +30 -0
- data/lib/igniter/extensions/contracts/invariants/report.rb +45 -0
- data/lib/igniter/extensions/contracts/invariants/suite.rb +36 -0
- data/lib/igniter/extensions/contracts/invariants/violation.rb +39 -0
- data/lib/igniter/extensions/contracts/invariants_pack.rb +88 -0
- data/lib/igniter/extensions/contracts/journal_pack.rb +55 -0
- data/lib/igniter/extensions/contracts/language/formula_pack.rb +185 -0
- data/lib/igniter/extensions/contracts/language/piecewise_pack.rb +166 -0
- data/lib/igniter/extensions/contracts/language/scale_pack.rb +147 -0
- data/lib/igniter/extensions/contracts/lookup_pack.rb +50 -0
- data/lib/igniter/extensions/contracts/mcp/creator_session.rb +105 -0
- data/lib/igniter/extensions/contracts/mcp/tool_argument.rb +35 -0
- data/lib/igniter/extensions/contracts/mcp/tool_definition.rb +33 -0
- data/lib/igniter/extensions/contracts/mcp/tool_result.rb +28 -0
- data/lib/igniter/extensions/contracts/mcp_pack.rb +335 -0
- data/lib/igniter/extensions/contracts/provenance/builder.rb +80 -0
- data/lib/igniter/extensions/contracts/provenance/lineage.rb +59 -0
- data/lib/igniter/extensions/contracts/provenance/node_trace.rb +53 -0
- data/lib/igniter/extensions/contracts/provenance/text_formatter.rb +62 -0
- data/lib/igniter/extensions/contracts/provenance_pack.rb +52 -0
- data/lib/igniter/extensions/contracts/reactive/builder.rb +43 -0
- data/lib/igniter/extensions/contracts/reactive/dispatch_result.rb +59 -0
- data/lib/igniter/extensions/contracts/reactive/engine.rb +79 -0
- data/lib/igniter/extensions/contracts/reactive/event.rb +36 -0
- data/lib/igniter/extensions/contracts/reactive/matcher.rb +20 -0
- data/lib/igniter/extensions/contracts/reactive/plan.rb +58 -0
- data/lib/igniter/extensions/contracts/reactive/subscription.rb +29 -0
- data/lib/igniter/extensions/contracts/reactive_pack.rb +169 -0
- data/lib/igniter/extensions/contracts/saga/compensation.rb +25 -0
- data/lib/igniter/extensions/contracts/saga/compensation_record.rb +28 -0
- data/lib/igniter/extensions/contracts/saga/compensation_set.rb +47 -0
- data/lib/igniter/extensions/contracts/saga/formatter.rb +39 -0
- data/lib/igniter/extensions/contracts/saga/result.rb +56 -0
- data/lib/igniter/extensions/contracts/saga/runner.rb +124 -0
- data/lib/igniter/extensions/contracts/saga_pack.rb +56 -0
- data/lib/igniter/extensions/contracts.rb +445 -0
- data/lib/igniter/extensions.rb +6 -0
- data/lib/igniter-extensions.rb +3 -0
- metadata +152 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Igniter
|
|
4
|
+
module Extensions
|
|
5
|
+
module Contracts
|
|
6
|
+
module Creator
|
|
7
|
+
class Scaffold
|
|
8
|
+
SUPPORTED_KINDS = %i[feature operational bundle].freeze
|
|
9
|
+
|
|
10
|
+
attr_reader :name, :kind, :namespace, :profile, :scope
|
|
11
|
+
|
|
12
|
+
def initialize(name:, kind:, namespace:, profile:, scope:)
|
|
13
|
+
@name = normalize_name(name)
|
|
14
|
+
@kind = normalize_kind(kind)
|
|
15
|
+
@namespace = normalize_namespace(namespace)
|
|
16
|
+
@profile = profile
|
|
17
|
+
@scope = scope
|
|
18
|
+
freeze
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def pack_class_name
|
|
22
|
+
"#{camelize(name)}Pack"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def pack_constant
|
|
26
|
+
"#{namespace}::#{pack_class_name}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def namespace_path
|
|
30
|
+
namespace.split("::").map { |part| underscore(part) }.join("/")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def pack_file_path
|
|
34
|
+
"#{scope.root}/#{namespace_path}/#{name}_pack.rb"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def spec_file_path
|
|
38
|
+
"#{scope.spec_root}/#{namespace_path}/#{name}_pack_spec.rb"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def example_file_path
|
|
42
|
+
"#{scope.example_root}/#{name}_pack.rb"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def readme_file_path
|
|
46
|
+
scope.readme_path
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def files
|
|
50
|
+
{
|
|
51
|
+
pack_file_path => pack_template,
|
|
52
|
+
spec_file_path => spec_template,
|
|
53
|
+
example_file_path => example_template,
|
|
54
|
+
readme_file_path => readme_template
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def summary
|
|
59
|
+
{
|
|
60
|
+
name: name,
|
|
61
|
+
kind: kind,
|
|
62
|
+
namespace: namespace,
|
|
63
|
+
profile: profile.to_h,
|
|
64
|
+
scope: scope.to_h,
|
|
65
|
+
pack_constant: pack_constant,
|
|
66
|
+
files: files.keys
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def to_h
|
|
71
|
+
summary.merge(files: files)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def normalize_name(name)
|
|
77
|
+
name.to_s.strip.gsub(/_pack\z/, "").downcase
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def normalize_kind(kind)
|
|
81
|
+
value = kind.to_sym
|
|
82
|
+
return value if SUPPORTED_KINDS.include?(value)
|
|
83
|
+
|
|
84
|
+
raise ArgumentError, "unsupported creator scaffold kind #{kind.inspect}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def normalize_namespace(namespace)
|
|
88
|
+
value = namespace.to_s.strip
|
|
89
|
+
return value unless value.empty?
|
|
90
|
+
|
|
91
|
+
"MyCompany::IgniterPacks"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def camelize(value)
|
|
95
|
+
value.split("_").map(&:capitalize).join
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def underscore(value)
|
|
99
|
+
value.gsub(/([a-z\d])([A-Z])/, "\\1_\\2").downcase
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def pack_template
|
|
103
|
+
case kind
|
|
104
|
+
when :feature then feature_pack_template
|
|
105
|
+
when :operational then operational_pack_template
|
|
106
|
+
when :bundle then bundle_pack_template
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def spec_template
|
|
111
|
+
case kind
|
|
112
|
+
when :feature then feature_spec_template
|
|
113
|
+
when :operational then operational_spec_template
|
|
114
|
+
when :bundle then bundle_spec_template
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def example_template
|
|
119
|
+
case kind
|
|
120
|
+
when :feature then feature_example_template
|
|
121
|
+
when :operational then operational_example_template
|
|
122
|
+
when :bundle then bundle_example_template
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def readme_template
|
|
127
|
+
<<~MARKDOWN
|
|
128
|
+
# #{pack_class_name}
|
|
129
|
+
|
|
130
|
+
#{pack_class_name} is a #{kind} pack built on top of `igniter-contracts`.
|
|
131
|
+
|
|
132
|
+
## Files
|
|
133
|
+
|
|
134
|
+
- `#{pack_file_path}` — pack implementation
|
|
135
|
+
- `#{spec_file_path}` — package-owned spec
|
|
136
|
+
- `#{example_file_path}` — runnable example
|
|
137
|
+
|
|
138
|
+
## Authoring Profile
|
|
139
|
+
|
|
140
|
+
- `#{profile.name}`
|
|
141
|
+
- capabilities: `#{profile.capabilities.join("`, `")}`
|
|
142
|
+
- registry seams: `#{profile.registry_capabilities.join("`, `")}`
|
|
143
|
+
#{runtime_dependency_hints_markdown}
|
|
144
|
+
#{development_dependency_hints_markdown}
|
|
145
|
+
#{development_hints_markdown}
|
|
146
|
+
|
|
147
|
+
## Target Scope
|
|
148
|
+
|
|
149
|
+
- `#{scope.name}`
|
|
150
|
+
- pack root: `#{scope.root}`
|
|
151
|
+
- spec root: `#{scope.spec_root}`
|
|
152
|
+
- example root: `#{scope.example_root}`
|
|
153
|
+
#{packaging_hints_markdown}
|
|
154
|
+
|
|
155
|
+
## Recommended Workflow
|
|
156
|
+
|
|
157
|
+
1. Fill in the pack implementation using only public `Igniter::Contracts` APIs.
|
|
158
|
+
2. Run the generated spec and example.
|
|
159
|
+
3. Use `Igniter::Extensions::Contracts.audit_pack(#{pack_constant}, environment)` to verify completeness.
|
|
160
|
+
4. Only then decide whether the pack remains app-local or becomes a distributable gem.
|
|
161
|
+
MARKDOWN
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def feature_pack_template
|
|
165
|
+
<<~RUBY
|
|
166
|
+
# frozen_string_literal: true
|
|
167
|
+
|
|
168
|
+
module #{namespace}
|
|
169
|
+
module #{pack_class_name}
|
|
170
|
+
class << self
|
|
171
|
+
def manifest
|
|
172
|
+
Igniter::Contracts::PackManifest.new(#{feature_manifest_body})
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def install_into(kernel)
|
|
176
|
+
kernel.nodes.register(:#{name}, Igniter::Contracts::NodeType.new(kind: :#{name}, metadata: { category: :custom }))
|
|
177
|
+
kernel.dsl_keywords.register(:#{name}, #{name}_keyword)
|
|
178
|
+
kernel.validators.register(:#{name}_sources, method(:validate_#{name}_sources))
|
|
179
|
+
kernel.runtime_handlers.register(:#{name}, method(:handle_#{name}))
|
|
180
|
+
kernel
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def #{name}_keyword
|
|
184
|
+
Igniter::Contracts::DslKeyword.new(:#{name}) do |name, from:, builder:|
|
|
185
|
+
builder.add_operation(kind: :#{name}, name: name, from: from.to_sym)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def validate_#{name}_sources(operations:, profile: nil) # rubocop:disable Lint/UnusedMethodArgument
|
|
190
|
+
[]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def handle_#{name}(operation:, state:, **)
|
|
194
|
+
state.fetch(operation.attributes.fetch(:from).to_sym)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
RUBY
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def operational_pack_template
|
|
203
|
+
<<~RUBY
|
|
204
|
+
# frozen_string_literal: true
|
|
205
|
+
|
|
206
|
+
module #{namespace}
|
|
207
|
+
module #{pack_class_name}
|
|
208
|
+
class << self
|
|
209
|
+
def manifest
|
|
210
|
+
Igniter::Contracts::PackManifest.new(#{operational_manifest_body})
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def install_into(kernel)
|
|
214
|
+
kernel.effects.register(:#{name}, method(:apply_#{name}))
|
|
215
|
+
kernel.executors.register(:#{name}_inline, method(:execute_#{name}_inline))
|
|
216
|
+
kernel
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def apply_#{name}(invocation:)
|
|
220
|
+
invocation.payload
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def execute_#{name}_inline(invocation:)
|
|
224
|
+
invocation.runtime.execute(
|
|
225
|
+
invocation.compiled_graph,
|
|
226
|
+
inputs: invocation.inputs,
|
|
227
|
+
profile: invocation.profile
|
|
228
|
+
)
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
RUBY
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def bundle_pack_template
|
|
237
|
+
<<~RUBY
|
|
238
|
+
# frozen_string_literal: true
|
|
239
|
+
|
|
240
|
+
module #{namespace}
|
|
241
|
+
module #{pack_class_name}
|
|
242
|
+
class << self
|
|
243
|
+
def manifest
|
|
244
|
+
Igniter::Contracts::PackManifest.new(
|
|
245
|
+
name: :#{name},
|
|
246
|
+
#{bundle_manifest_body}
|
|
247
|
+
)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def install_into(kernel)
|
|
251
|
+
#{bundle_diagnostic_install_lines}
|
|
252
|
+
kernel
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
#{bundle_diagnostic_contributor_template}
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
RUBY
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def feature_spec_template
|
|
263
|
+
<<~RUBY
|
|
264
|
+
# frozen_string_literal: true
|
|
265
|
+
|
|
266
|
+
RSpec.describe #{pack_constant} do
|
|
267
|
+
it "installs a feature node pack through public contracts APIs" do
|
|
268
|
+
environment = Igniter::Contracts.with(described_class)
|
|
269
|
+
|
|
270
|
+
result = environment.run(inputs: { source: "value" }) do
|
|
271
|
+
input :source
|
|
272
|
+
#{name} :result, from: :source
|
|
273
|
+
output :result
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
expect(result.output(:result)).to eq("value")
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
RUBY
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def operational_spec_template
|
|
283
|
+
<<~RUBY
|
|
284
|
+
# frozen_string_literal: true
|
|
285
|
+
|
|
286
|
+
RSpec.describe #{pack_constant} do
|
|
287
|
+
it "installs effect and executor seams through public contracts APIs" do
|
|
288
|
+
environment = Igniter::Contracts.with(described_class)
|
|
289
|
+
|
|
290
|
+
compiled = environment.compile do
|
|
291
|
+
input :amount
|
|
292
|
+
output :amount
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
result = environment.execute_with(:#{name}_inline, compiled, inputs: { amount: 10 })
|
|
296
|
+
|
|
297
|
+
expect(environment.apply_effect(:#{name}, payload: { amount: 10 })).to eq(amount: 10)
|
|
298
|
+
expect(result.output(:amount)).to eq(10)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
RUBY
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def bundle_spec_template
|
|
305
|
+
<<~RUBY
|
|
306
|
+
# frozen_string_literal: true
|
|
307
|
+
|
|
308
|
+
RSpec.describe #{pack_constant} do
|
|
309
|
+
it "installs a bundle pack without depending on contracts internals" do
|
|
310
|
+
profile = Igniter::Contracts.build_profile(described_class)
|
|
311
|
+
|
|
312
|
+
expect(profile.pack_names).to include(:#{name})
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
RUBY
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def feature_example_template
|
|
319
|
+
<<~RUBY
|
|
320
|
+
# frozen_string_literal: true
|
|
321
|
+
|
|
322
|
+
require "igniter/contracts"
|
|
323
|
+
|
|
324
|
+
environment = Igniter::Contracts.with(#{pack_constant})
|
|
325
|
+
|
|
326
|
+
result = environment.run(inputs: { source: "hello" }) do
|
|
327
|
+
input :source
|
|
328
|
+
#{name} :result, from: :source
|
|
329
|
+
output :result
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
audit = Igniter::Extensions::Contracts.audit_pack(#{pack_constant}, environment)
|
|
333
|
+
|
|
334
|
+
puts "creator_example_output=\#{result.output(:result)}"
|
|
335
|
+
puts "creator_example_audit_ok=\#{audit.ok?}"
|
|
336
|
+
RUBY
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def operational_example_template
|
|
340
|
+
<<~RUBY
|
|
341
|
+
# frozen_string_literal: true
|
|
342
|
+
|
|
343
|
+
require "igniter/contracts"
|
|
344
|
+
|
|
345
|
+
environment = Igniter::Contracts.with(#{pack_constant})
|
|
346
|
+
|
|
347
|
+
compiled = environment.compile do
|
|
348
|
+
input :amount
|
|
349
|
+
output :amount
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
effect_result = environment.apply_effect(:#{name}, payload: { amount: 10 })
|
|
353
|
+
execution_result = environment.execute_with(:#{name}_inline, compiled, inputs: { amount: 15 })
|
|
354
|
+
|
|
355
|
+
puts "creator_effect_payload=\#{effect_result.inspect}"
|
|
356
|
+
puts "creator_execution_output=\#{execution_result.output(:amount)}"
|
|
357
|
+
RUBY
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def bundle_example_template
|
|
361
|
+
<<~RUBY
|
|
362
|
+
# frozen_string_literal: true
|
|
363
|
+
|
|
364
|
+
require "igniter/contracts"
|
|
365
|
+
|
|
366
|
+
profile = Igniter::Contracts.build_profile(#{pack_constant})
|
|
367
|
+
|
|
368
|
+
puts "creator_bundle_profile=\#{profile.pack_names.join(',')}"
|
|
369
|
+
RUBY
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def runtime_dependency_hints_markdown
|
|
373
|
+
return "" if profile.runtime_dependency_hints.empty?
|
|
374
|
+
|
|
375
|
+
" - runtime dependency packs: `#{profile.runtime_dependency_hints.join("`, `")}`"
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def development_dependency_hints_markdown
|
|
379
|
+
return "" if profile.development_dependency_hints.empty?
|
|
380
|
+
|
|
381
|
+
" - development tool packs: `#{profile.development_dependency_hints.join("`, `")}`"
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
def development_hints_markdown
|
|
385
|
+
return "" if profile.development_hints.empty?
|
|
386
|
+
|
|
387
|
+
" - development hints: `#{profile.development_hints.join("`; `")}`"
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
def packaging_hints_markdown
|
|
391
|
+
return "" if scope.packaging_hints.empty?
|
|
392
|
+
|
|
393
|
+
" - packaging hints: `#{scope.packaging_hints.join("`; `")}`"
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
def bundle_manifest_body
|
|
397
|
+
lines = ["metadata: { category: :bundle }"]
|
|
398
|
+
append_runtime_dependency_manifest_line(lines)
|
|
399
|
+
lines << "registry_contracts: [Igniter::Contracts::PackManifest.diagnostic(:#{name}_summary)]" if profile.capability?(:diagnostic)
|
|
400
|
+
lines.join(",\n ")
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def feature_manifest_body
|
|
404
|
+
lines = [
|
|
405
|
+
"name: :#{name}",
|
|
406
|
+
"node_contracts: [Igniter::Contracts::PackManifest.node(:#{name})]",
|
|
407
|
+
"registry_contracts: [Igniter::Contracts::PackManifest.validator(:#{name}_sources)]"
|
|
408
|
+
]
|
|
409
|
+
append_runtime_dependency_manifest_line(lines)
|
|
410
|
+
lines.join(",\n ")
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def operational_manifest_body
|
|
414
|
+
lines = [
|
|
415
|
+
"name: :#{name}",
|
|
416
|
+
<<~RUBY.chomp
|
|
417
|
+
registry_contracts: [
|
|
418
|
+
Igniter::Contracts::PackManifest.effect(:#{name}),
|
|
419
|
+
Igniter::Contracts::PackManifest.executor(:#{name}_inline)
|
|
420
|
+
]
|
|
421
|
+
RUBY
|
|
422
|
+
]
|
|
423
|
+
append_runtime_dependency_manifest_line(lines)
|
|
424
|
+
lines.join(",\n ")
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def append_runtime_dependency_manifest_line(lines)
|
|
428
|
+
return lines if profile.runtime_dependency_hints.empty?
|
|
429
|
+
|
|
430
|
+
lines << "requires_packs: [#{profile.runtime_dependency_hints.join(", ")}]"
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def bundle_diagnostic_install_lines
|
|
434
|
+
return "# no diagnostics contributor for this profile" unless profile.capability?(:diagnostic)
|
|
435
|
+
|
|
436
|
+
"kernel.diagnostics_contributors.register(:#{name}_summary, #{name}_summary)"
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def bundle_diagnostic_contributor_template
|
|
440
|
+
return "" unless profile.capability?(:diagnostic)
|
|
441
|
+
|
|
442
|
+
<<~RUBY.chomp
|
|
443
|
+
def #{name}_summary
|
|
444
|
+
Module.new do
|
|
445
|
+
module_function
|
|
446
|
+
|
|
447
|
+
def augment(report:, result:, profile:) # rubocop:disable Lint/UnusedMethodArgument
|
|
448
|
+
report.add_section(:#{name}_summary, {
|
|
449
|
+
output_names: result.outputs.keys.sort,
|
|
450
|
+
pack_names: profile.pack_names.sort
|
|
451
|
+
})
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
RUBY
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Igniter
|
|
4
|
+
module Extensions
|
|
5
|
+
module Contracts
|
|
6
|
+
module Creator
|
|
7
|
+
class Scope
|
|
8
|
+
PRESETS = {
|
|
9
|
+
app_local: {
|
|
10
|
+
root: "app/lib",
|
|
11
|
+
spec_root: "spec/lib",
|
|
12
|
+
example_root: "examples",
|
|
13
|
+
readme_path: "docs/igniter-packs/README.md",
|
|
14
|
+
packaging_hints: [
|
|
15
|
+
"keep the pack close to the host app while the API is still moving",
|
|
16
|
+
"prefer app-local namespacing before extracting a shared gem"
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
monorepo_package: {
|
|
20
|
+
root: "lib",
|
|
21
|
+
spec_root: "spec",
|
|
22
|
+
example_root: "examples",
|
|
23
|
+
readme_path: "README.md",
|
|
24
|
+
packaging_hints: [
|
|
25
|
+
"add package-owned specs and a runnable example before promoting the pack",
|
|
26
|
+
"keep the public entrypoint independent from igniter-core and contracts internals"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
standalone_gem: {
|
|
30
|
+
root: "lib",
|
|
31
|
+
spec_root: "spec",
|
|
32
|
+
example_root: "examples",
|
|
33
|
+
readme_path: "README.md",
|
|
34
|
+
packaging_hints: [
|
|
35
|
+
"publish only after the pack has a stable public entrypoint and package-owned example",
|
|
36
|
+
"treat the pack as a distributable gem with a small explicit surface"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
attr_reader :name, :root, :spec_root, :example_root, :readme_path, :packaging_hints
|
|
42
|
+
|
|
43
|
+
def self.available
|
|
44
|
+
PRESETS.keys
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.build(scope)
|
|
48
|
+
preset = PRESETS.fetch(scope.to_sym) do
|
|
49
|
+
raise ArgumentError, "unknown creator scope #{scope.inspect}"
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
new(name: scope, **preset)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def initialize(name:, root:, spec_root:, example_root:, readme_path:, packaging_hints:)
|
|
56
|
+
@name = name.to_sym
|
|
57
|
+
@root = root
|
|
58
|
+
@spec_root = spec_root
|
|
59
|
+
@example_root = example_root
|
|
60
|
+
@readme_path = readme_path
|
|
61
|
+
@packaging_hints = packaging_hints.dup.freeze
|
|
62
|
+
freeze
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def to_h
|
|
66
|
+
{
|
|
67
|
+
name: name,
|
|
68
|
+
root: root,
|
|
69
|
+
spec_root: spec_root,
|
|
70
|
+
example_root: example_root,
|
|
71
|
+
readme_path: readme_path,
|
|
72
|
+
packaging_hints: packaging_hints
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|