Skip to content

Commit

Permalink
Merge pull request #2 from KarolinaZyskowska/master
Browse files Browse the repository at this point in the history
Filtering paths by regex.
  • Loading branch information
michalstocki authored Dec 12, 2016
2 parents c1dcd83 + 2d41bfd commit d322cd4
Show file tree
Hide file tree
Showing 29 changed files with 2,031 additions and 17 deletions.
87 changes: 85 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,97 @@ The filter matches all paths defined in the input JSON against the given regular

## Usage

### as node.js package
We can use the swagger-json-filter from a js code, givng the input JSON string and options of filtering:
```
const swaggerJsonFilter = require('swagger-json-filter');
const output = swaggerJsonFilter(inputJsonString, {
includePaths: "^\/estimates\/.*"
});
```

### as command line tool
Install package globally
```
npm install -g swagger-json-filter
```

then you can provide contents of the JSON file to the stdin:
then you can provide contents of the above JSON file to the stdin:
```
cat input.json | swagger-json-filter --include-paths="^\/estimates\/.*" > output.json
```

input.json:
```
{
"swagger": "2.0",
"info": {"version": "0.0.0", "title": "Simple API"},
"paths": {
"/estimates/price": {
"get": {
"responses": {
"200": {
"description": "An array of price estimates by product",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/PriceEstimate"
}}}}}},
"/me": {
"get": {
"responses": {
"200": {
"description": "Unexpected error",
"schema": {
"$ref": "#/definitions/Error"
}}}}}
},
"definitions": {
"PriceEstimate": {
"type": "object",
"properties": {
"product_id": {
"type": "string",
"description": "Unique identifier"
}}},
"Error": {
"type": "object",
"properties": {
"code": {
"type": "integer",
"format": "int32"
}}}
}
}
```

and we recive following output.json
```
cat swagger.json | swagger-json-filter --include-paths="\/api\/.*" > filtered-swagger.json
{
"swagger": "2.0",
"info": {"version": "0.0.0", "title": "Simple API"},
"paths": {
"/estimates/price": {
"get": {
"responses": {
"200": {
"description": "An array of price estimates by product",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/PriceEstimate"
}}}}}}
},
"definitions": {
"PriceEstimate": {
"type": "object",
"properties": {
"product_id": {
"type": "string",
"description": "Unique identifier"
}}}
}
}
```

## Acknowledgements ##
Expand Down
20 changes: 20 additions & 0 deletions bin/swagger-json-filter
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env node
const swaggerJsonFilter = require('../src/index');

const stdin = process.openStdin();
let inputJson = '';
stdin.on('data', function (chunk) {
inputJson += chunk;
});

stdin.on('end', function () {
const output = swaggerJsonFilter(inputJson, getProgram());
console.log(output);
});

function getProgram() {
let program = require('commander');
program.option('-i, --include-paths <include-paths>', 'Keep only paths matching the given JavaScript regex')
.parse(process.argv);
return program;
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@
"name": "swagger-json-filter",
"version": "0.0.1",
"description": "Node.js command-line tool for filtering swagger documentation (swagger.json)",
"main": "index.js",
"main": "src/index.js",
"bin": "bin/swagger-json-filter",
"directories": {
"test": "test"
},
"dependencies": {
"commander": "^2.9.0",
"flat": "^2.0.1"
},
"devDependencies": {
"json-diff": "^0.3.1"
Expand Down
79 changes: 79 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const flatten = require('flat');

module.exports = function (inputJson, options) {
const pathRegex = new RegExp(options.includePaths);
inputJson = JSON.parse(inputJson);
const paths = inputJson.paths;

let definitionsMap = {};
for (const path in paths) {
searchReferencesFor(paths[path], inputJson, definitionsMap);
}
removeUnwantedKeys(paths, pathRegex);
let whiteList = {};
for (const path in paths) {
searchReferencesFor(paths[path], inputJson, whiteList);
}

clearMismatchedElements(inputJson, definitionsMap, whiteList);
return filterJson(inputJson, whiteList);
};

function removeUnwantedKeys(objectToFilter, keyRegex) {
for (const key in objectToFilter) {
if (!keyRegex.test(key)) {
delete objectToFilter[key];
}
}
}

function isObject(value) {
return (typeof value === 'object');
}

function saveReference(defLocalizationName, defName, definitionsMap) {
definitionsMap[defLocalizationName] = definitionsMap[defLocalizationName] || [];
definitionsMap[defLocalizationName].push(defName);
}

function shouldSaveReference(defLocalizationName, defName, definitionsMap) {
return !definitionsMap[defLocalizationName] || definitionsMap[defLocalizationName].indexOf(defName) < 0;
}

function searchReferencesFor(definition, inputJson, definitionsMap) {
const flattenDefinition = flatten(definition);
for (const key in flattenDefinition) {
let value = flattenDefinition[key];
if (key.includes('$ref')) {
const [defLocalizationName, defName] = value.slice(2).split('/');
const nestedDefinition = inputJson[defLocalizationName][defName];
if (shouldSaveReference(defLocalizationName, defName, definitionsMap)) {
saveReference(defLocalizationName, defName, definitionsMap);
if (isObject(nestedDefinition)) {
searchReferencesFor(nestedDefinition, inputJson, definitionsMap);
}
}
}
}
}

function clearMismatchedElements(obj, someList, whiteList) {
for (const key in someList) {
if (!whiteList.hasOwnProperty(key)) {
obj[key] = {};
}
}
}

function filterJson(inputJson, definitionsMap) {
for (const defLocalizationName in definitionsMap) {
let expectedDefNames = definitionsMap[defLocalizationName];
for (const key in inputJson[defLocalizationName]) {
if (expectedDefNames.indexOf(key) < 0) {
delete inputJson[defLocalizationName][key];
}
}
}
return JSON.stringify(inputJson);
}

3 changes: 0 additions & 3 deletions test/paths/include-paths-filter-definitions/test.sh

This file was deleted.

Loading

0 comments on commit d322cd4

Please sign in to comment.