Skip to content

Commit 72b94c1

Browse files
eraydbighappyface
authored andcommitted
Add URI translation, package:// URI scheme & bundle spec schemas (#362)
* Add URI translation for retrieval & add local copies of spec schema * Use dist copies of schemas No need to keep duplicate files around in package://tests/fixtures/ if we're distributing them for users anyway. * Move package:// translation after all other rules Allows users to rewrite to package:// targets and still have the URI work.
1 parent ef3ee83 commit 72b94c1

File tree

8 files changed

+424
-417
lines changed

8 files changed

+424
-417
lines changed

dist/schema/json-schema-draft-03.json

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-03/schema#",
3+
"id": "http://json-schema.org/draft-03/schema#",
4+
"type": "object",
5+
6+
"properties": {
7+
"type": {
8+
"type": [ "string", "array" ],
9+
"items": {
10+
"type": [ "string", { "$ref": "#" } ]
11+
},
12+
"uniqueItems": true,
13+
"default": "any"
14+
},
15+
16+
"properties": {
17+
"type": "object",
18+
"additionalProperties": { "$ref": "#" },
19+
"default": {}
20+
},
21+
22+
"patternProperties": {
23+
"type": "object",
24+
"additionalProperties": { "$ref": "#" },
25+
"default": {}
26+
},
27+
28+
"additionalProperties": {
29+
"type": [ { "$ref": "#" }, "boolean" ],
30+
"default": {}
31+
},
32+
33+
"items": {
34+
"type": [ { "$ref": "#" }, "array" ],
35+
"items": { "$ref": "#" },
36+
"default": {}
37+
},
38+
39+
"additionalItems": {
40+
"type": [ { "$ref": "#" }, "boolean" ],
41+
"default": {}
42+
},
43+
44+
"required": {
45+
"type": "boolean",
46+
"default": false
47+
},
48+
49+
"dependencies": {
50+
"type": "object",
51+
"additionalProperties": {
52+
"type": [ "string", "array", { "$ref": "#" } ],
53+
"items": {
54+
"type": "string"
55+
}
56+
},
57+
"default": {}
58+
},
59+
60+
"minimum": {
61+
"type": "number"
62+
},
63+
64+
"maximum": {
65+
"type": "number"
66+
},
67+
68+
"exclusiveMinimum": {
69+
"type": "boolean",
70+
"default": false
71+
},
72+
73+
"exclusiveMaximum": {
74+
"type": "boolean",
75+
"default": false
76+
},
77+
78+
"minItems": {
79+
"type": "integer",
80+
"minimum": 0,
81+
"default": 0
82+
},
83+
84+
"maxItems": {
85+
"type": "integer",
86+
"minimum": 0
87+
},
88+
89+
"uniqueItems": {
90+
"type": "boolean",
91+
"default": false
92+
},
93+
94+
"pattern": {
95+
"type": "string",
96+
"format": "regex"
97+
},
98+
99+
"minLength": {
100+
"type": "integer",
101+
"minimum": 0,
102+
"default": 0
103+
},
104+
105+
"maxLength": {
106+
"type": "integer"
107+
},
108+
109+
"enum": {
110+
"type": "array",
111+
"minItems": 1,
112+
"uniqueItems": true
113+
},
114+
115+
"default": {
116+
"type": "any"
117+
},
118+
119+
"title": {
120+
"type": "string"
121+
},
122+
123+
"description": {
124+
"type": "string"
125+
},
126+
127+
"format": {
128+
"type": "string"
129+
},
130+
131+
"divisibleBy": {
132+
"type": "number",
133+
"minimum": 0,
134+
"exclusiveMinimum": true,
135+
"default": 1
136+
},
137+
138+
"disallow": {
139+
"type": [ "string", "array" ],
140+
"items": {
141+
"type": [ "string", { "$ref": "#" } ]
142+
},
143+
"uniqueItems": true
144+
},
145+
146+
"extends": {
147+
"type": [ { "$ref": "#" }, "array" ],
148+
"items": { "$ref": "#" },
149+
"default": {}
150+
},
151+
152+
"id": {
153+
"type": "string",
154+
"format": "uri"
155+
},
156+
157+
"$ref": {
158+
"type": "string",
159+
"format": "uri"
160+
},
161+
162+
"$schema": {
163+
"type": "string",
164+
"format": "uri"
165+
}
166+
},
167+
168+
"dependencies": {
169+
"exclusiveMinimum": "minimum",
170+
"exclusiveMaximum": "maximum"
171+
},
172+
173+
"default": {}
174+
}

dist/schema/json-schema-draft-04.json

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
{
2+
"id": "http://json-schema.org/draft-04/schema#",
3+
"$schema": "http://json-schema.org/draft-04/schema#",
4+
"description": "Core schema meta-schema",
5+
"definitions": {
6+
"schemaArray": {
7+
"type": "array",
8+
"minItems": 1,
9+
"items": { "$ref": "#" }
10+
},
11+
"positiveInteger": {
12+
"type": "integer",
13+
"minimum": 0
14+
},
15+
"positiveIntegerDefault0": {
16+
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
17+
},
18+
"simpleTypes": {
19+
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
20+
},
21+
"stringArray": {
22+
"type": "array",
23+
"items": { "type": "string" },
24+
"minItems": 1,
25+
"uniqueItems": true
26+
}
27+
},
28+
"type": "object",
29+
"properties": {
30+
"id": {
31+
"type": "string",
32+
"format": "uri"
33+
},
34+
"$schema": {
35+
"type": "string",
36+
"format": "uri"
37+
},
38+
"title": {
39+
"type": "string"
40+
},
41+
"description": {
42+
"type": "string"
43+
},
44+
"default": {},
45+
"multipleOf": {
46+
"type": "number",
47+
"minimum": 0,
48+
"exclusiveMinimum": true
49+
},
50+
"maximum": {
51+
"type": "number"
52+
},
53+
"exclusiveMaximum": {
54+
"type": "boolean",
55+
"default": false
56+
},
57+
"minimum": {
58+
"type": "number"
59+
},
60+
"exclusiveMinimum": {
61+
"type": "boolean",
62+
"default": false
63+
},
64+
"maxLength": { "$ref": "#/definitions/positiveInteger" },
65+
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
66+
"pattern": {
67+
"type": "string",
68+
"format": "regex"
69+
},
70+
"additionalItems": {
71+
"anyOf": [
72+
{ "type": "boolean" },
73+
{ "$ref": "#" }
74+
],
75+
"default": {}
76+
},
77+
"items": {
78+
"anyOf": [
79+
{ "$ref": "#" },
80+
{ "$ref": "#/definitions/schemaArray" }
81+
],
82+
"default": {}
83+
},
84+
"maxItems": { "$ref": "#/definitions/positiveInteger" },
85+
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
86+
"uniqueItems": {
87+
"type": "boolean",
88+
"default": false
89+
},
90+
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
91+
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
92+
"required": { "$ref": "#/definitions/stringArray" },
93+
"additionalProperties": {
94+
"anyOf": [
95+
{ "type": "boolean" },
96+
{ "$ref": "#" }
97+
],
98+
"default": {}
99+
},
100+
"definitions": {
101+
"type": "object",
102+
"additionalProperties": { "$ref": "#" },
103+
"default": {}
104+
},
105+
"properties": {
106+
"type": "object",
107+
"additionalProperties": { "$ref": "#" },
108+
"default": {}
109+
},
110+
"patternProperties": {
111+
"type": "object",
112+
"additionalProperties": { "$ref": "#" },
113+
"default": {}
114+
},
115+
"dependencies": {
116+
"type": "object",
117+
"additionalProperties": {
118+
"anyOf": [
119+
{ "$ref": "#" },
120+
{ "$ref": "#/definitions/stringArray" }
121+
]
122+
}
123+
},
124+
"enum": {
125+
"type": "array",
126+
"minItems": 1,
127+
"uniqueItems": true
128+
},
129+
"type": {
130+
"anyOf": [
131+
{ "$ref": "#/definitions/simpleTypes" },
132+
{
133+
"type": "array",
134+
"items": { "$ref": "#/definitions/simpleTypes" },
135+
"minItems": 1,
136+
"uniqueItems": true
137+
}
138+
]
139+
},
140+
"allOf": { "$ref": "#/definitions/schemaArray" },
141+
"anyOf": { "$ref": "#/definitions/schemaArray" },
142+
"oneOf": { "$ref": "#/definitions/schemaArray" },
143+
"not": { "$ref": "#" }
144+
},
145+
"dependencies": {
146+
"exclusiveMaximum": [ "maximum" ],
147+
"exclusiveMinimum": [ "minimum" ]
148+
},
149+
"default": {}
150+
}

src/JsonSchema/Uri/UriRetriever.php

+37-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
*/
2525
class UriRetriever implements BaseUriRetrieverInterface
2626
{
27+
/**
28+
* @var array Map of URL translations
29+
*/
30+
protected $translationMap = array(
31+
// use local copies of the spec schemas
32+
'|^https?://json-schema.org/draft-(0[34])/schema#?|' => 'package://dist/schema/json-schema-draft-$1.json'
33+
);
34+
2735
/**
2836
* @var null|UriRetrieverInterface
2937
*/
@@ -134,7 +142,7 @@ public function resolvePointer($jsonSchema, $uri)
134142
/**
135143
* {@inheritdoc}
136144
*/
137-
public function retrieve($uri, $baseUri = null)
145+
public function retrieve($uri, $baseUri = null, $translate = true)
138146
{
139147
$resolver = new UriResolver();
140148
$resolvedUri = $fetchUri = $resolver->resolve($uri, $baseUri);
@@ -146,6 +154,11 @@ public function retrieve($uri, $baseUri = null)
146154
$fetchUri = $resolver->generate($arParts);
147155
}
148156

157+
// apply URI translations
158+
if ($translate) {
159+
$fetchUri = $this->translate($fetchUri);
160+
}
161+
149162
$jsonSchema = $this->loadSchema($fetchUri);
150163

151164
// Use the JSON pointer if specified
@@ -291,4 +304,27 @@ public function isValid($uri)
291304

292305
return !empty($components);
293306
}
307+
308+
/**
309+
* Set a URL translation rule
310+
*/
311+
public function setTranslation($from, $to)
312+
{
313+
$this->translationMap[$from] = $to;
314+
}
315+
316+
/**
317+
* Apply URI translation rules
318+
*/
319+
public function translate($uri)
320+
{
321+
foreach ($this->translationMap as $from => $to) {
322+
$uri = preg_replace($from, $to, $uri);
323+
}
324+
325+
// translate references to local files within the json-schema package
326+
$uri = preg_replace('|^package://|', sprintf('file://%s/', realpath(__DIR__ . '/../../..')), $uri);
327+
328+
return $uri;
329+
}
294330
}

0 commit comments

Comments
 (0)