Skip to content

Commit

Permalink
Merge pull request #1 from Bunk/feature-parse-ast
Browse files Browse the repository at this point in the history
Support a better parsing engine by using AST's and visitors
  • Loading branch information
Bunk committed Mar 11, 2017
2 parents f41498b + 88e9f4b commit adda5e5
Show file tree
Hide file tree
Showing 16 changed files with 929 additions and 164 deletions.
27 changes: 27 additions & 0 deletions .vscode/launch.json
@@ -0,0 +1,27 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Test",
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"cwd": "${workspaceRoot}",
"args": [
"--no-timeouts",
"-r", "lib/test/helpers/",
"-R", "spec",
"lib/src/**/*.spec.js"
],
"stopOnEntry": false,
"preLaunchTask": "build:test",
"env": {
"NODE_ENV": "test"
},
"sourceMaps": true,
"outFiles": [
"${workspaceRoot}/lib/**"
]
}
]
}
20 changes: 20 additions & 0 deletions .vscode/tasks.json
@@ -0,0 +1,20 @@
{
"version": "0.1.0",
"command": "npm",
"isShellCommand": true,
"args": ["run"],
"showOutput": "silent",
"tasks": [ {
"taskName": "build",
"isBuildCommand": false,
"isTestCommand": false,
"showOutput": "silent",
"args": []
}, {
"taskName": "build:test",
"isBuildCommand": false,
"isTestCommand": false,
"showOutput": "silent",
"args": []
} ]
}
11 changes: 5 additions & 6 deletions package.json
Expand Up @@ -6,19 +6,18 @@
"scripts": {
"lint": "eslint ./src",
"clean": "rm -rf ./lib && rm -rf .nyc_output && rm -rf coverage",
"build": "npm run clean && npm run build:run -- --ignore spec.js",
"build:run": "babel src -d lib --source-maps inline --copy-files",
"build:debug": "npm run clean && npm run build:run",
"build": "npm run clean && babel src --out-dir lib --source-maps inline --copy-files --ignore spec.js",
"build:test": "npm run clean && babel test --out-dir lib/test --source-maps inline --copy-files && babel src --out-dir lib/src --source-maps inline --copy-files",
"build:watch": "npm run build -- --watch",
"pretest": "npm run lint",
"test": "npm run coveralls",
"test:run": "NODE_ENV=test mocha --compilers js:babel-register --timeout 5000 -r ./test/helpers/ -R spec",
"test:all": "npm run test:run -- 'src/**/*.spec.js'",
"test:watch": "npm run test:all -- -w",
"cover": "nyc -r text-summary -r html -- npm run test:all",
"coveralls": "nyc npm run test:all && nyc report -r text-lcov | coveralls",
"cover:watch": "nodemon --exec \"npm run cover\" --watch ./src --watch ./test",
"cover:show": "open \"file://$PWD/coverage/index.html\"",
"pretest": "npm run lint",
"prepublish": "npm test && npm run build"
"prepublish": "npm run lint && npm run build && npm run cover"
},
"dependencies": {
"lodash": "^4.17.2"
Expand Down
11 changes: 9 additions & 2 deletions src/index.js
@@ -1,4 +1,11 @@
const parser = require( "./parser" );
const parse = require( "./parser" );
const TopologyVisitor = require( "./visitors/topologyBuilder" );

module.exports = {
parse: parser
parse( dsl ) {
const ast = parse( dsl );
const visitor = new TopologyVisitor();
visitor.visit( ast );
return visitor.topology;
}
};
124 changes: 85 additions & 39 deletions src/parser.spec.js → src/index.spec.js
@@ -1,41 +1,47 @@
/* eslint-disable max-lines, no-magic-numbers */
/* eslint-env mocha */
const parser = require( "./parser" );
const data = require( "./parser.spec.json" );
const parser = require( "./index" );
const data = require( "./index.spec.json" );
const { assert } = testHelpers;

describe( "topologyParser", () => {
describe( "Topology Parser", () => {
let topology;

context( "parsing exchanges separately", () => {
beforeEach( () => {
topology = parser( data[ "exchanges-only" ] );
topology = parser.parse( data[ "exchanges-only" ] );
} );

it( "should parse all exchanges defined", () => {
assert.deepEqual( topology.exchanges, {
"defined.exchange": {
fat: {
name: "defined.exchange",
type: "fanout",
durable: true,
internal: true,
autoDelete: true,
alternateExchange: "alternate.exchange",
arguments: {
custom: "value"
custom: "value",
canonical: true,
unsupported: "value"
}
},
minimal: {
name: "minimal",
type: "fanout"
}
} );
} );

it( "should not contain any extra properties", () => {
assert.notProperty( topology.exchanges[ "defined.exchange" ], "unsupported" );
assert.notProperty( topology.exchanges.fat, "unsupported" );
} );
} );

context( "parsing queues separately", () => {
beforeEach( () => {
topology = parser( data[ "queues-only" ] );
topology = parser.parse( data[ "queues-only" ] );
} );

it( "should parse the normal queue definition", () => {
Expand All @@ -49,7 +55,8 @@ describe( "topologyParser", () => {
maxPriority: 1,
messageTtl: 500,
arguments: {
custom: "value"
custom: "value",
unsupported: "value"
}
} );
} );
Expand All @@ -68,37 +75,61 @@ describe( "topologyParser", () => {
} );

context( "parsing bindings separately", () => {
beforeEach( () => {
topology = parser( data[ "bindings-only" ] );
context( "given normal, unique bindings", () => {
beforeEach( () => {
topology = parser.parse( data[ "bindings-only" ] );
} );

it( "should parse the queue binding", () => {
assert.lengthOf( topology.bindings.queues, 2 );
assert.deepEqual( topology.bindings.queues[ 0 ], {
exchange: "target.exchange",
target: "target.queue",
pattern: "#"
} );
assert.deepEqual( topology.bindings.queues[ 1 ], {
exchange: "target.exchange",
target: "target.queue",
pattern: "*.message"
} );
} );

it( "should parse the exchange binding", () => {
assert.lengthOf( topology.bindings.exchanges, 1 );
assert.deepEqual( topology.bindings.exchanges[ 0 ], {
exchange: "target.exchange",
target: "target.exchange.topic",
pattern: ""
} );
} );
} );

it( "should parse the queue binding", () => {
assert.lengthOf( topology.bindings.queues, 2 );
assert.deepEqual( topology.bindings.queues[ 0 ], {
exchange: "target.exchange",
target: "target.queue",
pattern: "#"
context( "given duplicate bindings", () => {
beforeEach( () => {
topology = parser.parse( data[ "bindings-only-duplicates" ] );
} );
assert.deepEqual( topology.bindings.queues[ 1 ], {
exchange: "target.exchange",
target: "target.queue",
pattern: "*.message"

it( "should parse only one binding", () => {
assert.lengthOf( topology.bindings.queues, 1 );
} );
} );

it( "should parse the exchange binding", () => {
assert.lengthOf( topology.bindings.exchanges, 1 );
assert.deepEqual( topology.bindings.exchanges[ 0 ], {
exchange: "target.exchange",
target: "target.exchange.topic",
pattern: ""
context( "given root bindings referencing undefined queues", () => {
it( "should throw an error", () => {
assert.throws( () => parser.parse( data[ "bindings-missing-queues" ] ) );
} );
} );

context( "given root bindings referencing undefined exchanges", () => {
it( "should throw an error", () => {
assert.throws( () => parser.parse( data[ "bindings-missing-exchanges" ] ) );
} );
} );
} );

context( "parsing embedded alternate exchanges", () => {
beforeEach( () => {
topology = parser( data[ "embedded-alt-exchange" ] );
topology = parser.parse( data[ "embedded-alt-exchange" ] );
} );

it( "should create the alternate exchange", () => {
Expand All @@ -113,7 +144,7 @@ describe( "topologyParser", () => {

context( "parsing embedded dead letter exchanges", () => {
beforeEach( () => {
topology = parser( data[ "embedded-deadletter-exchange" ] );
topology = parser.parse( data[ "embedded-deadletter-exchange" ] );
} );

it( "should create the dead-letter exchange", () => {
Expand All @@ -126,7 +157,7 @@ describe( "topologyParser", () => {

context( "parsing embedded queue bindings", () => {
beforeEach( () => {
topology = parser( data[ "embedded-queue-bindings" ] );
topology = parser.parse( data[ "embedded-queue-bindings" ] );
} );

it( "should create the embedded queue from the binding", () => {
Expand All @@ -147,18 +178,26 @@ describe( "topologyParser", () => {
} );
} );

it( "should create the queue binding", () => {
it( "should create the queue binding for the embedded queue", () => {
assert.deepEqual( topology.bindings.queues[ 0 ], {
exchange: "defined.exchange",
target: "defined.queue",
pattern: "*.message"
} );
} );

it( "should create the queue binding for the referenced queue", async () => {
assert.deepEqual( topology.bindings.queues[ 1 ], {
exchange: "defined.exchange",
target: "referenced.queue",
pattern: "#"
} );
} );
} );

context( "parsing embedded exchange bindings", () => {
beforeEach( () => {
topology = parser( data[ "embedded-exchange-bindings" ] );
topology = parser.parse( data[ "embedded-exchange-bindings" ] );
} );

it( "should create the embedded exchange from the binding", () => {
Expand All @@ -170,18 +209,26 @@ describe( "topologyParser", () => {
} );
} );

it( "should create the exchange binding", () => {
it( "should create the exchange binding for the embedded exchange", () => {
assert.deepEqual( topology.bindings.exchanges[ 0 ], {
exchange: "defined.exchange",
target: "defined.exchange.topic",
pattern: "#"
} );
} );

it( "should create the exchange binding for the reference", async () => {
assert.deepEqual( topology.bindings.exchanges[ 1 ], {
exchange: "defined.exchange",
target: "referenced.exchange",
pattern: "#"
} );
} );
} );

context( "parsing subscriptions", () => {
beforeEach( () => {
topology = parser( data.subscriptions );
topology = parser.parse( data.subscriptions );
} );

it( "should create the subscription exchange", () => {
Expand Down Expand Up @@ -216,7 +263,7 @@ describe( "topologyParser", () => {

context( "parsing subscriptions with embedded exchanges", () => {
beforeEach( () => {
topology = parser( data[ "embedded-subscriptions" ] );
topology = parser.parse( data[ "embedded-subscriptions" ] );
} );

it( "should create the subscription exchange", () => {
Expand Down Expand Up @@ -251,7 +298,7 @@ describe( "topologyParser", () => {

context( "named primitives", () => {
beforeEach( () => {
topology = parser( data[ "named-primitives" ] );
topology = parser.parse( data[ "named-primitives" ] );
} );

it( "should create an index-named queue", () => {
Expand All @@ -274,9 +321,8 @@ describe( "topologyParser", () => {
assert.deepEqual( topology.queues.ingress, { name: "ingress.queue" } );
} );

it( "should create an index-named queue for the embedded simple queue", () => {
assert.deepProperty( topology.queues, "simple" );
assert.deepEqual( topology.queues.simple, { name: "simple.queue" } );
it( "should not create an index-named queue for the referenced simple queue", () => {
assert.notProperty( topology.queues, "simple" );
} );
} );
} );

0 comments on commit adda5e5

Please sign in to comment.