Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Documentation/Architecture/SchemaAndRegex.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@ owned quotas. Compilation is a separate public operation.

JSONSchemaRegistry is an immutable bounded snapshot of explicitly supplied resource documents. Updating it produces a new snapshot. There is no automatic URLSession resolver or mutable global registry. A caller fetches resources through its own authorized application I/O before constructing the snapshot. Each compile consumes the selected snapshot within the compiler's own cumulative limits.

Packaged Draft 2020-12 resources retain their exact byte-size and SHA-256 checks.
On Apple platforms, a native SwiftPM test runner may be `Bundle.main` while the
schema code belongs to a nested `.xctest` bundle. After the existing app,
framework and executable locations, lookup checks the parent of that code-owner
`.xctest` for its sibling resource bundle. This is one fixed layout, not an
ancestor search or URL resolver. Lookup uses the same compilation meter; a
selected missing/corrupt payload throws an operational error without trying a
different payload. `Scripts/qualify_distribution.py` runs a public Swift Testing
consumer under the native backend in Debug and Release with resource overrides
removed, then preserves the standalone intact/missing/corrupt distribution cases.

Use JSONSchemaCompiler(options:).compile(document, registry:) throws -> CompiledJSONSchema and JSONSchemaValidator(options:).validate(instance, against:) throws -> JSONValidationResult. Compiled plans are checked Sendable and immutable; validators store configuration only. Plan IDs, resource IDs, keyword IDs and reference targets use bounded private indices. Avoid exposing upstream Schema, Context, OrderedDictionary or Regex types in signatures.

Compilation validates dialect declaration, required vocabularies, meta-schema constraints, identifiers, anchors and resolvable resources. Support Draft 2020-12 as the only standard dialect. Custom meta-schema declarations using supported vocabularies can be resolved from the snapshot; unsupported required vocabularies fail. Unknown annotations follow dialect rules. Keep format annotation distinct from assertion; do not turn content metadata into unconditional decoding of instance text.
Expand Down
18 changes: 16 additions & 2 deletions Scripts/qualify_distribution.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
"""Public consumer plus installed-resource failures; touch only owned build output."""
import argparse, hashlib, json, pathlib, subprocess, time
import argparse, hashlib, json, os, pathlib, re, subprocess, time
ROOT = pathlib.Path(__file__).resolve().parents[1]

def main():
p = argparse.ArgumentParser(); p.add_argument('--output', required=True); a = p.parse_args()
output = ROOT / a.output; output.mkdir(parents=True, exist_ok=True)
receipt = dict(status='failed', commands=[], resource_probes=3)
environment = os.environ.copy()
for key in ('PACKAGE_RESOURCE_BUNDLE_PATH', 'PACKAGE_RESOURCE_BUNDLE_URL'):
environment.pop(key, None)
def save(): (output/'distribution.json').write_text(json.dumps(receipt,indent=2)+'\n')
save()
def run(name, command, expected=None):
start = time.monotonic(); log = output / (name+'.log')
with log.open('w') as stream:
result = subprocess.run(command, cwd=ROOT, stdout=stream, stderr=subprocess.STDOUT, timeout=1800)
result = subprocess.run(command, cwd=ROOT, env=environment, stdout=stream, stderr=subprocess.STDOUT, timeout=1800)
text = log.read_text()
receipt['commands'].append(dict(command=command, exit_code=result.returncode, seconds=time.monotonic()-start,
log=log.name, sha256=hashlib.sha256(log.read_bytes()).hexdigest()))
save()
assert result.returncode == 0 and (expected is None or expected in text), name
return text.strip()
package = 'Tools/DistributionAcceptance'
# The native backend loads tests from a nested .xctest image under a helper.
# A standalone executable does not exercise its sibling-bundle discovery.
for configuration in ('debug', 'release'):
text = run('native-test-host-' + configuration,
['swift', 'test', '-c', configuration, '--build-system', 'native',
'--package-path', package, '--scratch-path', str(output / 'native-test-host')],
'DISTRIBUTION native_test_host nine_offline_resources exact_verdicts')
assert re.findall(r'Test run with (\d+) tests? in[^\n]*passed', text) == ['1'], 'Native host discovery changed'
receipt['native_test_host'] = dict(configurations=['debug', 'release'], functions=1,
backend='native', resource_overrides_used=False)
save()
run('build', ['swift','build','-c','release','--package-path',package])
directory = pathlib.Path(run('bin-path', ['swift','build','-c','release','--package-path',package,'--show-bin-path']))
executable = directory / 'DistributionAcceptance'
Expand Down
2 changes: 1 addition & 1 deletion Sources/JSONCLIEngine/CLIBuildIdentity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
// Generated by Scripts/generate_cli_identity.py; excludes this file.
// SHA-256 of the ordered Package.swift + Sources content manifest, not a Git commit.
package enum CLIBuildIdentity {
package static let revision = "sha256:138ae7e8bc2f4392db7aafaa000f60db5915658a1b34a55f12a9c27958da1312"
package static let revision = "sha256:52ec97c92df8f4518ecfbf604b895124915205e9ce6c509b05fa31f4aed62452"
package static let kind = "source-sha256"
}
12 changes: 11 additions & 1 deletion Sources/JSONSchema/Document/JSONSchemaBuiltins.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,22 @@ extension JSONSchemaRegistry {
#endif
if let directory = Bundle.main.resourceURL { candidates.append(directory) }
#if canImport(ObjectiveC)
if let directory = Bundle(for: JSONSchemaBundleAnchor.self).resourceURL { candidates.append(directory) }
let codeBundle = Bundle(for: JSONSchemaBundleAnchor.self)
if let directory = codeBundle.resourceURL { candidates.append(directory) }
#endif
candidates.append(Bundle.main.bundleURL)
if let command = CommandLine.arguments.first {
candidates.append(URL(fileURLWithPath: command).deletingLastPathComponent())
}
#if canImport(ObjectiveC)
// Native SwiftPM uses a helper as Bundle.main. The code-owner .xctest
// bundle has sibling resources. Search that fixed layout last; existing
// locations and corruption pins remain authoritative.
let ownerBundle = codeBundle.bundleURL
if ownerBundle.pathExtension == "xctest" {
candidates.append(ownerBundle.deletingLastPathComponent())
}
#endif
let root = try builtinResourceRoot(in: candidates, meter: &meter)
#endif
for (path, identifier, size, expectedHash) in files {
Expand Down
5 changes: 4 additions & 1 deletion Tools/DistributionAcceptance/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ let package = Package(
.product(name: "JSON", package: "Swift-JSON"),
.product(name: "JSONSchema", package: "Swift-JSON"),
.product(name: "JSONStreaming", package: "Swift-JSON"),
.product(name: "JSONPatch", package: "Swift-JSON")])],
.product(name: "JSONPatch", package: "Swift-JSON")]),
.testTarget(name: "SchemaResourceHostTests", dependencies: [
.product(name: "JSON", package: "Swift-JSON"),
.product(name: "JSONSchema", package: "Swift-JSON")])],
swiftLanguageModes: [.v6])
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
import Testing
import JSON
import JSONSchema

@Test func nativeTestHostLoadsPackagedSchemasWithoutOverrides() throws {
let registry = try JSONSchemaRegistry.draft2020_12()
#expect(registry.documents.count == 9)
let raw = try JSONParser().parse(#"{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"integer","minimum":9007199254740993}"#)
let plan = try JSONSchemaCompiler().compile(JSONSchemaDocument(raw), registry: registry)
#expect(try JSONSchemaValidator().validate(JSONParser().parse("9007199254740993"), against: plan).isValid)
#expect(try !JSONSchemaValidator().validate(JSONParser().parse("9007199254740992"), against: plan).isValid)
print("DISTRIBUTION native_test_host nine_offline_resources exact_verdicts")
}