igniter_lang 0.1.0.alpha.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.
- checksums.yaml +7 -0
- data/README.md +65 -0
- data/RELEASE_NOTES.md +137 -0
- data/bin/igc +7 -0
- data/lib/igniter_lang/assembler.rb +717 -0
- data/lib/igniter_lang/classifier.rb +405 -0
- data/lib/igniter_lang/cli.rb +76 -0
- data/lib/igniter_lang/compilation_report.rb +99 -0
- data/lib/igniter_lang/compiler_orchestrator.rb +362 -0
- data/lib/igniter_lang/compiler_profile_contract_validator.rb +286 -0
- data/lib/igniter_lang/compiler_result.rb +77 -0
- data/lib/igniter_lang/diagnostics.rb +125 -0
- data/lib/igniter_lang/fragment_registry_compatibility_adapter.rb +129 -0
- data/lib/igniter_lang/internal_profile_assembly.rb +199 -0
- data/lib/igniter_lang/internal_profile_assembly_source_packet.rb +175 -0
- data/lib/igniter_lang/internal_profile_static_data_carrier.rb +286 -0
- data/lib/igniter_lang/oof_fragment_registry.rb +802 -0
- data/lib/igniter_lang/parser.rb +1736 -0
- data/lib/igniter_lang/runtime_smoke.rb +80 -0
- data/lib/igniter_lang/semanticir_emitter.rb +847 -0
- data/lib/igniter_lang/temporal_access_runtime.rb +437 -0
- data/lib/igniter_lang/temporal_executor.rb +457 -0
- data/lib/igniter_lang/typechecker.rb +821 -0
- data/lib/igniter_lang/version.rb +5 -0
- data/lib/igniter_lang.rb +27 -0
- metadata +72 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Internal profile-assembly source packet.
|
|
4
|
+
#
|
|
5
|
+
# ISOLATION CONTRACT — this file must not:
|
|
6
|
+
# - be required from lib/igniter_lang.rb
|
|
7
|
+
# - integrate with parser/classifier/TypeChecker/SemanticIR/assembler/orchestrator
|
|
8
|
+
# - expose public API or CLI
|
|
9
|
+
# - read paths, manifests, loader reports, CompatibilityReports, or runtime state
|
|
10
|
+
# - write .igapp, .ilk, reports, sidecars, goldens, diagnostics, or CompilerResult fields
|
|
11
|
+
#
|
|
12
|
+
# Authorized by: LANG-R128-A
|
|
13
|
+
# Track: internal-profile-assembly-source-packet-implementation-v0
|
|
14
|
+
#
|
|
15
|
+
# Lifecycle wording:
|
|
16
|
+
# implementation_candidate = internal implementation boundary state
|
|
17
|
+
# finalized_internal = internal assembly state only; not PROP-036
|
|
18
|
+
# finalization, not compiler_profile_id, and not
|
|
19
|
+
# manifest/profile identity.
|
|
20
|
+
|
|
21
|
+
module IgniterLang
|
|
22
|
+
class InternalProfileAssemblySourcePacket
|
|
23
|
+
KIND = "compiler_profile_oof_registry_source_input"
|
|
24
|
+
FORMAT_VERSION = "0.1.0"
|
|
25
|
+
HELPER_KIND = "oof_fragment_registry_source"
|
|
26
|
+
VALIDATION_TARGET = "oof_fragment_registry_source_envelope_helper"
|
|
27
|
+
|
|
28
|
+
IMPLEMENTATION_CANDIDATE = "implementation_candidate"
|
|
29
|
+
FINALIZED_INTERNAL = "finalized_internal"
|
|
30
|
+
LIFECYCLE_STATES = [IMPLEMENTATION_CANDIDATE, FINALIZED_INTERNAL].freeze
|
|
31
|
+
|
|
32
|
+
DEFAULT_CLOSED_SURFACE_ASSERTIONS = {
|
|
33
|
+
"compiler_integration" => false,
|
|
34
|
+
"public_api_cli" => false,
|
|
35
|
+
"loader_report" => false,
|
|
36
|
+
"compatibility_report" => false,
|
|
37
|
+
"igapp_mutation" => false,
|
|
38
|
+
"prop036_manifest_change" => false,
|
|
39
|
+
"prop038_validator_report_change" => false,
|
|
40
|
+
"runtime_behavior" => false,
|
|
41
|
+
"production_behavior" => false,
|
|
42
|
+
"spark_surface" => false
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
def self.build(authority:, profile_candidate:, pack_descriptor_candidates:,
|
|
46
|
+
lifecycle_state: IMPLEMENTATION_CANDIDATE, closed_surface_assertions: {},
|
|
47
|
+
excluded_namespaces: nil)
|
|
48
|
+
new(
|
|
49
|
+
authority: authority,
|
|
50
|
+
profile_candidate: profile_candidate,
|
|
51
|
+
pack_descriptor_candidates: pack_descriptor_candidates,
|
|
52
|
+
lifecycle_state: lifecycle_state,
|
|
53
|
+
closed_surface_assertions: DEFAULT_CLOSED_SURFACE_ASSERTIONS.merge(
|
|
54
|
+
stringify_keys(closed_surface_assertions)
|
|
55
|
+
),
|
|
56
|
+
excluded_namespaces: excluded_namespaces
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def initialize(authority:, profile_candidate:, pack_descriptor_candidates:,
|
|
61
|
+
lifecycle_state:, closed_surface_assertions:, excluded_namespaces:)
|
|
62
|
+
unless LIFECYCLE_STATES.include?(lifecycle_state)
|
|
63
|
+
raise ArgumentError, "unsupported lifecycle_state #{lifecycle_state.inspect}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@authority = deep_copy(authority)
|
|
67
|
+
@profile_candidate = deep_copy(profile_candidate)
|
|
68
|
+
@pack_descriptor_candidates = deep_copy(pack_descriptor_candidates)
|
|
69
|
+
@lifecycle_state = lifecycle_state
|
|
70
|
+
@closed_surface_assertions = deep_copy(closed_surface_assertions)
|
|
71
|
+
@excluded_namespaces = deep_copy(excluded_namespaces)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
attr_reader :lifecycle_state
|
|
75
|
+
|
|
76
|
+
def to_h
|
|
77
|
+
packet = {
|
|
78
|
+
"kind" => KIND,
|
|
79
|
+
"format_version" => FORMAT_VERSION,
|
|
80
|
+
"lifecycle_state" => lifecycle_state,
|
|
81
|
+
"authority" => deep_copy(@authority),
|
|
82
|
+
"profile_candidate" => deep_copy(@profile_candidate),
|
|
83
|
+
"pack_descriptor_candidates" => deep_copy(@pack_descriptor_candidates),
|
|
84
|
+
"validation_target" => VALIDATION_TARGET,
|
|
85
|
+
"closed_surface_assertions" => deep_copy(@closed_surface_assertions)
|
|
86
|
+
}
|
|
87
|
+
packet["excluded_namespaces"] = deep_copy(@excluded_namespaces) if @excluded_namespaces
|
|
88
|
+
packet
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def to_helper_envelopes
|
|
92
|
+
packet = to_h
|
|
93
|
+
common = {
|
|
94
|
+
"kind" => HELPER_KIND,
|
|
95
|
+
"format_version" => FORMAT_VERSION,
|
|
96
|
+
"authority" => packet.fetch("authority"),
|
|
97
|
+
"closed_surface_assertions" => packet.fetch("closed_surface_assertions")
|
|
98
|
+
}
|
|
99
|
+
profile = packet.fetch("profile_candidate")
|
|
100
|
+
pack_candidates = packet.fetch("pack_descriptor_candidates")
|
|
101
|
+
|
|
102
|
+
profile_envelope = common.merge(
|
|
103
|
+
"source_mode" => "profile_candidate",
|
|
104
|
+
"profile_ref" => profile.fetch("profile_ref"),
|
|
105
|
+
"profile_contract_ref" => profile["profile_contract_ref"],
|
|
106
|
+
"row_authority_policy" => profile.fetch("row_authority_policy"),
|
|
107
|
+
"selected_pack_refs" => profile.fetch("selected_pack_refs"),
|
|
108
|
+
"pack_order" => profile.fetch("pack_order"),
|
|
109
|
+
"conflict_policy" => profile.fetch("conflict_policy"),
|
|
110
|
+
"pack_descriptor_candidates" => pack_candidates
|
|
111
|
+
)
|
|
112
|
+
profile_envelope["excluded_namespaces"] = packet.fetch("excluded_namespaces") if packet.key?("excluded_namespaces")
|
|
113
|
+
|
|
114
|
+
pack_envelopes = pack_candidates.map do |pack|
|
|
115
|
+
common.merge(
|
|
116
|
+
"source_mode" => "pack_descriptor_candidate",
|
|
117
|
+
"pack_ref" => pack.fetch("pack_ref"),
|
|
118
|
+
"slot_name" => pack.fetch("slot_name"),
|
|
119
|
+
"owner_pack_or_boundary" => pack.fetch("owner_pack_or_boundary"),
|
|
120
|
+
"row_authority_policy" => pack.fetch("row_authority_policy"),
|
|
121
|
+
"owned_oof_descriptors" => pack.fetch("owned_oof_descriptors"),
|
|
122
|
+
"owned_fragment_rows" => pack.fetch("owned_fragment_rows"),
|
|
123
|
+
"owned_support_markers" => pack.fetch("owned_support_markers")
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
{
|
|
128
|
+
"kind" => "mapped_oof_fragment_registry_source_envelopes",
|
|
129
|
+
"format_version" => FORMAT_VERSION,
|
|
130
|
+
"source_input_kind" => KIND,
|
|
131
|
+
"profile_envelope" => profile_envelope,
|
|
132
|
+
"pack_descriptor_envelopes" => pack_envelopes
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def validate_with(registry_validator:)
|
|
137
|
+
helper_envelopes = to_helper_envelopes
|
|
138
|
+
profile_validation = registry_validator.validate_source_envelope(
|
|
139
|
+
helper_envelopes.fetch("profile_envelope")
|
|
140
|
+
)
|
|
141
|
+
pack_validations = helper_envelopes.fetch("pack_descriptor_envelopes").map do |envelope|
|
|
142
|
+
registry_validator.validate_source_envelope(envelope)
|
|
143
|
+
end
|
|
144
|
+
valid = profile_validation.fetch("valid") &&
|
|
145
|
+
pack_validations.all? { |result| result.fetch("valid") }
|
|
146
|
+
result_state = valid ? FINALIZED_INTERNAL : lifecycle_state
|
|
147
|
+
|
|
148
|
+
{
|
|
149
|
+
"kind" => "internal_profile_assembly_source_packet_validation",
|
|
150
|
+
"format_version" => FORMAT_VERSION,
|
|
151
|
+
"valid" => valid,
|
|
152
|
+
"lifecycle_state" => lifecycle_state,
|
|
153
|
+
"result_lifecycle_state" => result_state,
|
|
154
|
+
"finalized_internal_meaning" =>
|
|
155
|
+
"internal assembly state only; not PROP-036 finalization, not compiler_profile_id, " \
|
|
156
|
+
"and not manifest/profile identity",
|
|
157
|
+
"source_packet" => to_h,
|
|
158
|
+
"helper_envelopes" => helper_envelopes,
|
|
159
|
+
"profile_validation" => profile_validation,
|
|
160
|
+
"pack_descriptor_validations" => pack_validations,
|
|
161
|
+
"closed_surface_assertions" => deep_copy(@closed_surface_assertions)
|
|
162
|
+
}
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def self.stringify_keys(hash)
|
|
166
|
+
hash.to_h.transform_keys(&:to_s)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def deep_copy(value)
|
|
170
|
+
Marshal.load(Marshal.dump(value))
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
private :deep_copy
|
|
174
|
+
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
require "json"
|
|
5
|
+
require_relative "internal_profile_assembly_source_packet"
|
|
6
|
+
|
|
7
|
+
module IgniterLang
|
|
8
|
+
class InternalProfileStaticDataCarrier
|
|
9
|
+
KIND = "internal_profile_static_data_carrier"
|
|
10
|
+
FORMAT_VERSION = "0.1.0"
|
|
11
|
+
STATIC_DATA_STATUSES = ["proof_local_only", "internal_test_seam_only"].freeze
|
|
12
|
+
|
|
13
|
+
DIAG_INVALID_SHAPE = "internal_profile_static_data_carrier.invalid_shape"
|
|
14
|
+
DIAG_UNSUPPORTED_KIND = "internal_profile_static_data_carrier.unsupported_kind"
|
|
15
|
+
DIAG_UNSUPPORTED_FORMAT_VERSION =
|
|
16
|
+
"internal_profile_static_data_carrier.unsupported_format_version"
|
|
17
|
+
DIAG_UNSUPPORTED_STATIC_DATA_STATUS =
|
|
18
|
+
"internal_profile_static_data_carrier.unsupported_static_data_status"
|
|
19
|
+
DIAG_INVALID_AUTHORITY = "internal_profile_static_data_carrier.invalid_authority"
|
|
20
|
+
DIAG_MISSING_PROFILE_CANDIDATE =
|
|
21
|
+
"internal_profile_static_data_carrier.missing_profile_candidate"
|
|
22
|
+
DIAG_MISSING_PACK_DESCRIPTOR_CANDIDATES =
|
|
23
|
+
"internal_profile_static_data_carrier.missing_pack_descriptor_candidates"
|
|
24
|
+
DIAG_SURFACE_OPEN = "internal_profile_static_data_carrier.surface_open"
|
|
25
|
+
DIAG_FORBIDDEN_FIELD = "internal_profile_static_data_carrier.forbidden_field"
|
|
26
|
+
DIAG_PACKET_BUILD_FAILED = "internal_profile_static_data_carrier.packet_build_failed"
|
|
27
|
+
|
|
28
|
+
ACCEPTED_AUTHORITY_KINDS = ["proof_only", "design_accepted"].freeze
|
|
29
|
+
ACCEPTED_CANON_STATUSES = ["non_canon", "accepted_design"].freeze
|
|
30
|
+
|
|
31
|
+
FORBIDDEN_FIELDS = %w[
|
|
32
|
+
compiler_profile_id
|
|
33
|
+
compiler_profile_id_source
|
|
34
|
+
compiler_profile_source
|
|
35
|
+
profile_source
|
|
36
|
+
default_profile
|
|
37
|
+
named_profile
|
|
38
|
+
profile_discovery
|
|
39
|
+
igapp_path
|
|
40
|
+
compilation_report_path
|
|
41
|
+
loader_report
|
|
42
|
+
compatibility_report
|
|
43
|
+
compiler_result
|
|
44
|
+
manifest
|
|
45
|
+
sidecar
|
|
46
|
+
artifact_hash
|
|
47
|
+
runtime_ready
|
|
48
|
+
production_ready
|
|
49
|
+
spark_ready
|
|
50
|
+
demo_ready
|
|
51
|
+
public
|
|
52
|
+
discovery
|
|
53
|
+
loader
|
|
54
|
+
report
|
|
55
|
+
artifact
|
|
56
|
+
runtime
|
|
57
|
+
spark
|
|
58
|
+
production
|
|
59
|
+
demo
|
|
60
|
+
].freeze
|
|
61
|
+
|
|
62
|
+
def self.build(static_data:)
|
|
63
|
+
new(static_data)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def initialize(static_data)
|
|
67
|
+
@raw_static_data = static_data
|
|
68
|
+
@static_data = normalize_hash(static_data)
|
|
69
|
+
@packet_build_diagnostics = []
|
|
70
|
+
@diagnostics = validate_static_data
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def to_h
|
|
74
|
+
{
|
|
75
|
+
"kind" => KIND,
|
|
76
|
+
"format_version" => FORMAT_VERSION,
|
|
77
|
+
"valid" => valid_shape?,
|
|
78
|
+
"static_data_status" => static_data_status_output,
|
|
79
|
+
"authority" => authority_output,
|
|
80
|
+
"profile_candidate" => deep_copy(@static_data["profile_candidate"]),
|
|
81
|
+
"pack_descriptor_candidates" => deep_copy(pack_descriptor_candidates),
|
|
82
|
+
"excluded_namespaces" => deep_copy(excluded_namespaces),
|
|
83
|
+
"diagnostics" => diagnostics,
|
|
84
|
+
"static_data_digest" => static_data_digest,
|
|
85
|
+
"closed_surface_assertions" => closed_surface_assertions_output
|
|
86
|
+
}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def valid_shape?
|
|
90
|
+
diagnostics.empty?
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def diagnostics
|
|
94
|
+
deep_copy(@diagnostics + @packet_build_diagnostics)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def to_source_packet
|
|
98
|
+
return nil unless valid_shape?
|
|
99
|
+
|
|
100
|
+
IgniterLang::InternalProfileAssemblySourcePacket.build(
|
|
101
|
+
authority: deep_copy(@static_data.fetch("authority")),
|
|
102
|
+
profile_candidate: deep_copy(@static_data.fetch("profile_candidate")),
|
|
103
|
+
pack_descriptor_candidates: deep_copy(@static_data.fetch("pack_descriptor_candidates")),
|
|
104
|
+
lifecycle_state: IgniterLang::InternalProfileAssemblySourcePacket::IMPLEMENTATION_CANDIDATE,
|
|
105
|
+
closed_surface_assertions: deep_copy(closed_surface_assertions),
|
|
106
|
+
excluded_namespaces: deep_copy(excluded_namespaces)
|
|
107
|
+
)
|
|
108
|
+
rescue StandardError => e
|
|
109
|
+
record_packet_build_failure(e)
|
|
110
|
+
nil
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def static_data_digest
|
|
114
|
+
Digest::SHA256.hexdigest(JSON.generate(canonicalize(carrier_material)))[0, 24]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
private
|
|
118
|
+
|
|
119
|
+
def validate_static_data
|
|
120
|
+
diags = []
|
|
121
|
+
|
|
122
|
+
unless @raw_static_data.is_a?(Hash)
|
|
123
|
+
diags << diag(DIAG_INVALID_SHAPE, "static_data must be a Hash")
|
|
124
|
+
return diags
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
unless @static_data["kind"] == KIND
|
|
128
|
+
diags << diag(DIAG_UNSUPPORTED_KIND, "static_data kind is not supported")
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
unless @static_data["format_version"] == FORMAT_VERSION
|
|
132
|
+
diags << diag(DIAG_UNSUPPORTED_FORMAT_VERSION, "static_data format_version is not supported")
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
unless STATIC_DATA_STATUSES.include?(@static_data["static_data_status"])
|
|
136
|
+
diags << diag(DIAG_UNSUPPORTED_STATIC_DATA_STATUS, "static_data status is not supported")
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
diags << diag(DIAG_INVALID_AUTHORITY, "authority is outside internal proof/design scope") unless valid_authority?
|
|
140
|
+
|
|
141
|
+
unless @static_data["profile_candidate"].is_a?(Hash)
|
|
142
|
+
diags << diag(DIAG_MISSING_PROFILE_CANDIDATE, "profile_candidate must be present")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
unless @static_data["pack_descriptor_candidates"].is_a?(Array) &&
|
|
146
|
+
@static_data["pack_descriptor_candidates"].any?
|
|
147
|
+
diags << diag(DIAG_MISSING_PACK_DESCRIPTOR_CANDIDATES,
|
|
148
|
+
"pack_descriptor_candidates must be a non-empty Array")
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
unless closed_surface_assertions.is_a?(Hash)
|
|
152
|
+
diags << diag(DIAG_INVALID_SHAPE, "closed_surface_assertions must be a Hash when present")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if closed_surface_assertions.is_a?(Hash) &&
|
|
156
|
+
closed_surface_assertions.values.any? { |value| value == true }
|
|
157
|
+
diags << diag(DIAG_SURFACE_OPEN, "closed_surface_assertions must remain closed")
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
forbidden_field_count.times do
|
|
161
|
+
diags << diag(DIAG_FORBIDDEN_FIELD, "forbidden field is not allowed in internal carrier input")
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
diags
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def valid_authority?
|
|
168
|
+
authority = @static_data["authority"]
|
|
169
|
+
return false unless authority.is_a?(Hash)
|
|
170
|
+
|
|
171
|
+
ACCEPTED_AUTHORITY_KINDS.include?(authority["authority_kind"]) &&
|
|
172
|
+
ACCEPTED_CANON_STATUSES.include?(authority["canon_status"]) &&
|
|
173
|
+
authority["authority_ref"].to_s.strip != ""
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def forbidden_field_count
|
|
177
|
+
count_forbidden_keys(@static_data)
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def count_forbidden_keys(value)
|
|
181
|
+
case value
|
|
182
|
+
when Hash
|
|
183
|
+
value.sum do |key, nested|
|
|
184
|
+
(FORBIDDEN_FIELDS.include?(key.to_s) ? 1 : 0) + count_forbidden_keys(nested)
|
|
185
|
+
end
|
|
186
|
+
when Array
|
|
187
|
+
value.sum { |nested| count_forbidden_keys(nested) }
|
|
188
|
+
else
|
|
189
|
+
0
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def record_packet_build_failure(error)
|
|
194
|
+
return if @packet_build_diagnostics.any? do |existing|
|
|
195
|
+
existing["code"] == DIAG_PACKET_BUILD_FAILED
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
@packet_build_diagnostics << diag(DIAG_PACKET_BUILD_FAILED, "#{error.class}: packet build failed")
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def carrier_material
|
|
202
|
+
{
|
|
203
|
+
"kind" => @static_data["kind"],
|
|
204
|
+
"format_version" => @static_data["format_version"],
|
|
205
|
+
"static_data_status" => @static_data["static_data_status"],
|
|
206
|
+
"authority" => @static_data["authority"],
|
|
207
|
+
"profile_candidate" => @static_data["profile_candidate"],
|
|
208
|
+
"pack_descriptor_candidates" => pack_descriptor_candidates,
|
|
209
|
+
"excluded_namespaces" => excluded_namespaces,
|
|
210
|
+
"closed_surface_assertions" => closed_surface_assertions
|
|
211
|
+
}
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def static_data_status_output
|
|
215
|
+
status = @static_data["static_data_status"]
|
|
216
|
+
STATIC_DATA_STATUSES.include?(status) ? status : nil
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def authority_output
|
|
220
|
+
return deep_copy(@static_data["authority"]) if valid_authority?
|
|
221
|
+
|
|
222
|
+
{ "valid" => false }
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def closed_surface_assertions_output
|
|
226
|
+
return {} unless closed_surface_assertions.is_a?(Hash)
|
|
227
|
+
return {} unless closed_surface_assertions.values.all?(false)
|
|
228
|
+
|
|
229
|
+
deep_copy(closed_surface_assertions)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def pack_descriptor_candidates
|
|
233
|
+
value = @static_data["pack_descriptor_candidates"]
|
|
234
|
+
value.is_a?(Array) ? value : []
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def excluded_namespaces
|
|
238
|
+
value = @static_data["excluded_namespaces"]
|
|
239
|
+
value.is_a?(Array) ? value : []
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def closed_surface_assertions
|
|
243
|
+
value = @static_data["closed_surface_assertions"]
|
|
244
|
+
value.nil? ? {} : value
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def normalize_hash(value)
|
|
248
|
+
return recursive_stringify(value) if value.is_a?(Hash)
|
|
249
|
+
|
|
250
|
+
{}
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def recursive_stringify(value)
|
|
254
|
+
case value
|
|
255
|
+
when Hash
|
|
256
|
+
value.to_h { |key, nested| [key.to_s, recursive_stringify(nested)] }
|
|
257
|
+
when Array
|
|
258
|
+
value.map { |nested| recursive_stringify(nested) }
|
|
259
|
+
else
|
|
260
|
+
value
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
def canonicalize(value)
|
|
265
|
+
case value
|
|
266
|
+
when Hash
|
|
267
|
+
value.keys.sort.to_h { |key| [key, canonicalize(value[key])] }
|
|
268
|
+
when Array
|
|
269
|
+
value.map { |inner| canonicalize(inner) }
|
|
270
|
+
else
|
|
271
|
+
value
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def deep_copy(value)
|
|
276
|
+
Marshal.load(Marshal.dump(value))
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def diag(code, message)
|
|
280
|
+
{
|
|
281
|
+
"code" => code,
|
|
282
|
+
"message" => message
|
|
283
|
+
}
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
end
|