Skip to content

Commit

Permalink
feat: add support for fragments (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
char0n authored Jan 2, 2024
1 parent 394ce27 commit 16f894f
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 143 deletions.
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ parseResult.result.success; // => true
'path-template': [Function: pathTemplate],
path: [Function: path],
query: [Function: query],
'query-literal': [Function: queryLiteral],
'query-marker': [Function: queryMarker],
fragment: [Function: fragment],
'fragment-marker': [Function: fragmentMarker],
slash: [Function: slash],
'path-literal': [Function: pathLiteral],
'template-expression': [Function: templateExpression],
Expand Down Expand Up @@ -171,7 +172,7 @@ import { test } from 'openapi-path-templating';
test('/pets/{petId}'); // => true
test('/a{petId}'); // => true
test('/pets'); // => true
test('/pets', { strict: true }); // => false (doesn't contain template-expression)
test('/pets', { strict: true }); // => false (doesn't contain any template-expression)
```

#### Resolution
Expand Down Expand Up @@ -212,12 +213,15 @@ The Path Templating is defined by the following [ABNF](https://tools.ietf.org/ht

```abnf
; OpenAPI Path Templating ABNF syntax
path-template = path [ query-marker query ]
path-template = path [ query-marker query ] [ fragment-marker fragment ]
path = slash *( path-segment slash ) [ path-segment ]
path-segment = 1*( path-literal / template-expression )
query = *( query-literal / template-expression )
query = *( query-literal )
query-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" / "&" / "=" )
query-marker = "?"
fragment = *( fragment-literal )
fragment-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" )
fragment-marker = "#"
slash = "/"
path-literal = 1*( unreserved / pct-encoded / sub-delims-no-slash / ":" / "@" )
template-expression = "{" template-expression-param-name "}"
Expand Down
12 changes: 12 additions & 0 deletions src/parse/callbacks/fragment-marker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { identifiers, utilities } from '#apg-lite';

const fragmentMarker = (state, chars, phraseIndex, phraseLength, data) => {
if (state === identifiers.SEM_PRE) {
data.push(['fragment-marker', utilities.charsToString(chars, phraseIndex, phraseLength)]);
} else if (state === identifiers.SEM_POST) {
/* not used in this example */
}
return identifiers.SEM_OK;
};

export default fragmentMarker;
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { identifiers, utilities } from '#apg-lite';

const queryLiteral = (state, chars, phraseIndex, phraseLength, data) => {
const fragment = (state, chars, phraseIndex, phraseLength, data) => {
if (state === identifiers.SEM_PRE) {
data.push(['query-literal', utilities.charsToString(chars, phraseIndex, phraseLength)]);
data.push(['fragment', utilities.charsToString(chars, phraseIndex, phraseLength)]);
} else if (state === identifiers.SEM_POST) {
/* not used in this example */
}
return identifiers.SEM_OK;
};

export default queryLiteral;
export default fragment;
6 changes: 4 additions & 2 deletions src/parse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import pathTemplateCallback from './callbacks/path-template.js';
import pathCallback from './callbacks/path.js';
import pathLiteralCallback from './callbacks/path-literal.js';
import queryCallback from './callbacks/query.js';
import queryLiteralCallback from './callbacks/query-literal.js';
import queryMarkerCallback from './callbacks/query-marker.js';
import fragmentCallback from './callbacks/fragment.js';
import fragmentMarkerCallback from './callbacks/fragment-marker.js';
import templateExpressionCallback from './callbacks/template-expression.js';
import templateExpressionParamNameCallback from './callbacks/template-expression-param-name.js';

Expand All @@ -20,8 +21,9 @@ const parse = (str) => {
parser.ast.callbacks['path-template'] = pathTemplateCallback;
parser.ast.callbacks['path'] = pathCallback;
parser.ast.callbacks['query'] = queryCallback;
parser.ast.callbacks['query-literal'] = queryLiteralCallback;
parser.ast.callbacks['query-marker'] = queryMarkerCallback;
parser.ast.callbacks['fragment'] = fragmentCallback;
parser.ast.callbacks['fragment-marker'] = fragmentMarkerCallback;
parser.ast.callbacks['slash'] = slashCallback;
parser.ast.callbacks['path-literal'] = pathLiteralCallback;
parser.ast.callbacks['template-expression'] = templateExpressionCallback;
Expand Down
7 changes: 5 additions & 2 deletions src/path-templating.bnf
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
; OpenAPI Path Templating ABNF syntax
path-template = path [ query-marker query ]
path-template = path [ query-marker query ] [ fragment-marker fragment ]
path = slash *( path-segment slash ) [ path-segment ]
path-segment = 1*( path-literal / template-expression )
query = *( query-literal / template-expression )
query = *( query-literal )
query-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" / "&" / "=" )
query-marker = "?"
fragment = *( fragment-literal )
fragment-literal = 1*( unreserved / pct-encoded / sub-delims / ":" / "@" / "/" / "?" )
fragment-marker = "#"
slash = "/"
path-literal = 1*( unreserved / pct-encoded / sub-delims-no-slash / ":" / "@" )
template-expression = "{" template-expression-param-name "}"
Expand Down
Loading

0 comments on commit 16f894f

Please sign in to comment.