Skip to content

Commit 6b4f27e

Browse files
authored
Merge pull request #150 from swaggerexpert/next
Align with official OpenAPI ABNF
2 parents adce587 + d5a577b commit 6b4f27e

File tree

13 files changed

+216
-346
lines changed

13 files changed

+216
-346
lines changed

NOTICE

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,9 @@ openapi-path-templating
22
Copyright 2023, Vladimír Gorej
33
openapi-path-templating is licensed under Apache 2.0 license.
44
Copy of the Apache 2.0 license can be found in `LICENSE` file.
5+
6+
OpenAPI Specification 3.1.x
7+
Copyright The Linux Foundation
8+
Fragments of the specification text are embedded in `README.md`.
9+
Definition of `template-expression-param-name` ABNF non-terminal is based on the OpenAPI Specification ABNF.
10+
Copy of the Apache 2.0 license can be found in `LICENSE` file.

README.md

Lines changed: 33 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
[![try on RunKit](https://img.shields.io/badge/try%20on-RunKit-brightgreen.svg?style=flat)](https://npm.runkit.com/openapi-path-templating)
88
[![Tidelift](https://tidelift.com/badges/package/npm/openapi-path-templating)](https://tidelift.com/subscription/pkg/npm-openapi-path-templating?utm_source=npm-openapi-path-templating&utm_medium=referral&utm_campaign=readme)
99

10-
[Path Templating](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#pathTemplating) allow defining values based on information that will only be available within the HTTP message in an actual API call.
11-
This mechanism is used by [Paths Object](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#paths-object)
12-
of [OpenAPI specification](https://github.com/OAI/OpenAPI-Specification).
10+
[OpenAPI Path Templating](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#path-templating) refers to the usage of template expressions, delimited by curly braces (`{}`), to mark a section of a URL path as replaceable using path parameters.
11+
Each template expression in the path MUST correspond to a path parameter that is included in the [Path Item](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#path-item-object) itself and/or in each of the Path Item's [Operations](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.1.md#operation-object).
12+
An exception is if the path item is empty, for example due to ACL constraints, matching path parameters are not required.
1313

14-
`openapi-path-templating` is a **parser**, **validator** and **resolver** for OpenAPI Path Templating. It supports
15-
Path Templating defined in following OpenAPI specification versions:
14+
`openapi-path-templating` is a **parser**, **validator**, and **resolver** for OpenAPI Path Templating,
15+
which played a [foundational role](https://github.com/OAI/OpenAPI-Specification/pull/4244) in defining the official ANBF grammar for OpenAPI Path Templating.
16+
17+
It supports Path Templating defined in following OpenAPI specification versions:
1618

1719
- [OpenAPI 2.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#pathTemplating)
1820
- [OpenAPI 3.0.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#pathTemplating)
@@ -63,7 +65,7 @@ You can install `openapi-path-templating` using `npm`:
6365
### Usage
6466

6567
`openapi-path-templating` currently supports **parsing**, **validation** and **resolution**.
66-
Both parser and validator are based on a superset of [ABNF](https://www.rfc-editor.org/rfc/rfc5234) ([SABNF](https://cs.github.com/ldthomas/apg-js2/blob/master/SABNF.md))
68+
Both parser and validator are based on a superset of [ABNF](https://www.rfc-editor.org/rfc/rfc5234) ([SABNF](https://github.com/ldthomas/apg-js2/blob/master/SABNF.md))
6769
and use [apg-lite](https://github.com/ldthomas/apg-lite) parser generator.
6870

6971
#### Parsing
@@ -89,17 +91,12 @@ parseResult.result.success; // => true
8991
length: 13,
9092
matched: 13,
9193
maxMatched: 13,
92-
maxTreeDepth: 18,
93-
nodeHits: 324
94+
maxTreeDepth: 20,
95+
nodeHits: 232
9496
},
9597
ast: fnast {
9698
callbacks: [
9799
'path-template': [Function: pathTemplate],
98-
path: [Function: path],
99-
query: [Function: query],
100-
'query-marker': [Function: queryMarker],
101-
fragment: [Function: fragment],
102-
'fragment-marker': [Function: fragmentMarker],
103100
slash: [Function: slash],
104101
'path-literal': [Function: pathLiteral],
105102
'template-expression': [Function: templateExpression],
@@ -134,7 +131,6 @@ After running the above code, **parts** variable has the following shape:
134131
```js
135132
[
136133
[ 'path-template', '/pets/{petId}' ],
137-
[ 'path', '/pets/{petId}' ],
138134
[ 'slash', '/' ],
139135
[ 'path-literal', 'pets' ],
140136
[ 'slash', '/' ],
@@ -156,29 +152,26 @@ After running the above code, **xml** variable has the following content:
156152

157153
```xml
158154
<?xml version="1.0" encoding="utf-8"?>
159-
<root nodes="7" characters="13">
155+
<root nodes="6" characters="13">
160156
<!-- input string -->
161157
/pets/{petId}
162158
<node name="path-template" index="0" length="13">
163159
/pets/{petId}
164-
<node name="path" index="0" length="13">
165-
/pets/{petId}
166-
<node name="slash" index="0" length="1">
167-
/
168-
</node><!-- name="slash" -->
169-
<node name="path-literal" index="1" length="4">
170-
pets
171-
</node><!-- name="path-literal" -->
172-
<node name="slash" index="5" length="1">
173-
/
174-
</node><!-- name="slash" -->
175-
<node name="template-expression" index="6" length="7">
176-
{petId}
177-
<node name="template-expression-param-name" index="7" length="5">
178-
petId
179-
</node><!-- name="template-expression-param-name" -->
180-
</node><!-- name="template-expression" -->
181-
</node><!-- name="path" -->
160+
<node name="slash" index="0" length="1">
161+
/
162+
</node><!-- name="slash" -->
163+
<node name="path-literal" index="1" length="4">
164+
pets
165+
</node><!-- name="path-literal" -->
166+
<node name="slash" index="5" length="1">
167+
/
168+
</node><!-- name="slash" -->
169+
<node name="template-expression" index="6" length="7">
170+
{petId}
171+
<node name="template-expression-param-name" index="7" length="5">
172+
petId
173+
</node><!-- name="template-expression-param-name" -->
174+
</node><!-- name="template-expression" -->
182175
</node><!-- name="path-template" -->
183176
</root>
184177
```
@@ -248,21 +241,17 @@ The Path Templating is defined by the following [ABNF](https://tools.ietf.org/ht
248241

249242
```abnf
250243
; OpenAPI Path Templating ABNF syntax
251-
path-template = path [ query-marker query ] [ fragment-marker fragment ]
252-
path = slash *( path-segment slash ) [ path-segment ]
253-
path-segment = 1*( path-literal / template-expression )
254-
query = *( query-literal )
255-
query-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" / "&" / "=" )
256-
query-marker = "?"
257-
fragment = *( fragment-literal )
258-
fragment-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" )
259-
fragment-marker = "#"
244+
; Aligned with RFC 3986 (https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
245+
path-template = slash [ path-template-nz ]
246+
path-template-nz = path-segment *( slash path-segment )
260247
slash = "/"
261-
path-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
248+
path-segment = 1*( path-literal / template-expression )
249+
path-literal = 1*pchar
262250
template-expression = "{" template-expression-param-name "}"
263-
template-expression-param-name = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
251+
template-expression-param-name = 1*pchar
264252
265253
; Characters definitions (from RFC 3986)
254+
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
266255
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
267256
pct-encoded = "%" HEXDIG HEXDIG
268257
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"

src/parse/callbacks/fragment-marker.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/parse/callbacks/fragment.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/parse/callbacks/path.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/parse/callbacks/query-marker.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/parse/callbacks/query.js

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/parse/index.js

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,7 @@ import { Ast as AST, Parser } from 'apg-lite';
33
import Grammar from '../path-templating.js';
44
import slashCallback from './callbacks/slash.js';
55
import pathTemplateCallback from './callbacks/path-template.js';
6-
import pathCallback from './callbacks/path.js';
76
import pathLiteralCallback from './callbacks/path-literal.js';
8-
import queryCallback from './callbacks/query.js';
9-
import queryMarkerCallback from './callbacks/query-marker.js';
10-
import fragmentCallback from './callbacks/fragment.js';
11-
import fragmentMarkerCallback from './callbacks/fragment-marker.js';
127
import templateExpressionCallback from './callbacks/template-expression.js';
138
import templateExpressionParamNameCallback from './callbacks/template-expression-param-name.js';
149

@@ -19,11 +14,6 @@ const parse = (pathTemplate) => {
1914

2015
parser.ast = new AST();
2116
parser.ast.callbacks['path-template'] = pathTemplateCallback;
22-
parser.ast.callbacks['path'] = pathCallback;
23-
parser.ast.callbacks['query'] = queryCallback;
24-
parser.ast.callbacks['query-marker'] = queryMarkerCallback;
25-
parser.ast.callbacks['fragment'] = fragmentCallback;
26-
parser.ast.callbacks['fragment-marker'] = fragmentMarkerCallback;
2717
parser.ast.callbacks['slash'] = slashCallback;
2818
parser.ast.callbacks['path-literal'] = pathLiteralCallback;
2919
parser.ast.callbacks['template-expression'] = templateExpressionCallback;

src/path-templating.bnf

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
; OpenAPI Path Templating ABNF syntax
2-
path-template = path [ query-marker query ] [ fragment-marker fragment ]
3-
path = slash *( path-segment slash ) [ path-segment ]
2+
path-template = slash *( path-segment slash ) [ path-segment ]
43
path-segment = 1*( path-literal / template-expression )
5-
query = *( query-literal )
6-
query-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" / "&" / "=" )
7-
query-marker = "?"
8-
fragment = *( fragment-literal )
9-
fragment-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" )
10-
fragment-marker = "#"
114
slash = "/"
12-
path-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
5+
path-literal = 1*pchar
136
template-expression = "{" template-expression-param-name "}"
14-
template-expression-param-name = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" )
7+
template-expression-param-name = 1*( %x00-79 / %x7C / %x7E-10FFFF ) ; every UTF8 character except { and } (from OpenAPI)
158

169
; Characters definitions (from RFC 3986)
10+
pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
1711
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
1812
pct-encoded = "%" HEXDIG HEXDIG
1913
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
2014
/ "*" / "+" / "," / ";" / "="
15+
16+
; Characters definitions (from RFC 5234)
2117
ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
2218
DIGIT = %x30-39 ; 0-9
2319
HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"

0 commit comments

Comments
 (0)