Skip to content
This repository has been archived by the owner on Nov 9, 2022. It is now read-only.

Commit

Permalink
Fix tests. Make IdGenerator pluggable
Browse files Browse the repository at this point in the history
  • Loading branch information
aslakhellesoy committed Dec 10, 2019
1 parent 620c18b commit e08cc10
Show file tree
Hide file tree
Showing 15 changed files with 162 additions and 173 deletions.
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
"devDependencies": {
"@types/mocha": "^5.2.7",
"@types/node": "^12.12.14",
"@types/uuid": "^3.4.6",
"mocha": "^6.2.2",
"nyc": "^14.1.1",
"prettier": "^1.19.1",
Expand All @@ -45,7 +44,6 @@
"dependencies": {
"commander": "^4.0.1",
"cucumber-messages": "7.0.0",
"source-map-support": "^0.5.16",
"uuid": "^3.3.3"
"source-map-support": "^0.5.16"
}
}
7 changes: 3 additions & 4 deletions src/AstBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import AstNode from './AstNode'
import { messages } from 'cucumber-messages'
import { messages, IdGenerator } from 'cucumber-messages'
import { RuleType, TokenType } from './Parser'
import Token from './Token'
import { AstBuilderException } from './Errors'
import { NewId } from './types'
import createLocation from './cli/createLocation'

export default class AstBuilder {
private stack: AstNode[]
private comments: messages.GherkinDocument.IComment[]
private readonly newId: NewId
private readonly newId: IdGenerator.NewId

constructor(newId: NewId) {
constructor(newId: IdGenerator.NewId) {
this.newId = newId
if (!newId) {
throw new Error('No newId')
Expand Down
97 changes: 97 additions & 0 deletions src/Gherkin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { PassThrough, pipeline, Readable } from 'stream'
import { BinaryToMessageStream, messages } from 'cucumber-messages'
import ParserMessageStream from './stream/ParserMessageStream'
import GherkinExe from './external/GherkinExe'
import fs from 'fs'
import SourceMessageStream from './stream/SourceMessageStream'
import Dialect from './Dialect'
import DIALECTS from './gherkin-languages.json'
import IGherkinOptions from './IGherkinOptions'
import makeGherkinOptions from './makeGherkinOptions'

function fromStream(stream: Readable, options: IGherkinOptions = {}) {
return pipeline(
stream,
new BinaryToMessageStream(messages.Envelope.decodeDelimited),
new ParserMessageStream(options)
)
}

function fromPaths(paths: string[], options: IGherkinOptions = {}): Readable {
options = makeGherkinOptions(options)

if (process.env.GHERKIN_EXECUTABLE) {
return new GherkinExe(
process.env.GHERKIN_EXECUTABLE,
paths,
[],
options
).messageStream()
}

const combinedMessageStream = new PassThrough({
writableObjectMode: true,
readableObjectMode: true,
})

function pipeSequentially() {
const path = paths.shift()
if (path !== undefined) {
const parserMessageStream = new ParserMessageStream(options)
parserMessageStream.on('end', () => {
pipeSequentially()
})

const end = paths.length === 0
fs.createReadStream(path, { encoding: 'utf-8' })
.pipe(new SourceMessageStream(path))
.pipe(parserMessageStream)
.pipe(combinedMessageStream, { end })
}
}
pipeSequentially()
return combinedMessageStream
}

function fromSources(
envelopes: messages.IEnvelope[],
options: IGherkinOptions = {}
): Readable {
options = makeGherkinOptions(options)
if (process.env.GHERKIN_EXECUTABLE) {
return new GherkinExe(
process.env.GHERKIN_EXECUTABLE,
[],
envelopes,
options
).messageStream()
}

const combinedMessageStream = new PassThrough({ objectMode: true })

function pipeSequentially() {
const envelope = envelopes.shift()
if (envelope !== undefined && envelope.source) {
const parserMessageStream = new ParserMessageStream(options)
parserMessageStream.pipe(combinedMessageStream, {
end: envelopes.length === 0,
})
parserMessageStream.on('end', pipeSequentially)
parserMessageStream.end(envelope)
}
}
pipeSequentially()

return combinedMessageStream
}

function dialects(): { [key: string]: Dialect } {
return DIALECTS
}

export default {
fromPaths,
fromStream,
fromSources,
dialects,
}
9 changes: 9 additions & 0 deletions src/IGherkinOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IdGenerator } from 'cucumber-messages'

export default interface IGherkinOptions {
defaultDialect?: string
includeSource?: boolean
includeGherkinDocument?: boolean
includePickles?: boolean
newId?: IdGenerator.NewId
}
11 changes: 0 additions & 11 deletions src/IdGenerator.ts

This file was deleted.

19 changes: 12 additions & 7 deletions src/cli/main.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { Command } from 'commander'
import packageJson from '../../package.json'
import gherkin from '../index'
import { IGherkinOptions } from '../types'
import { MessageToBinaryStream, MessageToNdjsonStream } from 'cucumber-messages'
import Gherkin from '../Gherkin'
import {
MessageToBinaryStream,
MessageToNdjsonStream,
IdGenerator,
} from 'cucumber-messages'
import { Readable, Transform } from 'stream'
import { incrementing, uuid } from '../IdGenerator'
import IGherkinOptions from '../IGherkinOptions'

const program = new Command()
program.version(packageJson.version)
Expand All @@ -25,13 +28,15 @@ const options: IGherkinOptions = {
includeSource: program.source,
includeGherkinDocument: program.ast,
includePickles: program.pickles,
newId: program.predictableIds ? incrementing() : uuid(),
newId: program.predictableIds
? IdGenerator.incrementing()
: IdGenerator.uuid(),
}

const messageStream =
paths.length === 0
? gherkin.fromStream((process.stdin as unknown) as Readable, options)
: gherkin.fromPaths(paths, options)
? Gherkin.fromStream((process.stdin as unknown) as Readable, options)
: Gherkin.fromPaths(paths, options)

let encodedStream: Transform
switch (program.format) {
Expand Down
2 changes: 1 addition & 1 deletion src/external/GherkinExe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { spawn, spawnSync } from 'child_process'
import { messages, BinaryToMessageStream } from 'cucumber-messages'
import { Readable } from 'stream'
import Dialect from '../Dialect'
import { IGherkinOptions } from '../types'
import IGherkinOptions from '../IGherkinOptions'

export default class GherkinExe {
constructor(
Expand Down
105 changes: 4 additions & 101 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,102 +1,5 @@
import { gherkinOptions, IGherkinOptions } from './types'
import { PassThrough, Readable, pipeline } from 'stream'
import ParserMessageStream from './stream/ParserMessageStream'
import fs from 'fs'
import SourceMessageStream from './stream/SourceMessageStream'
import { messages, BinaryToMessageStream } from 'cucumber-messages'
import DIALECTS from './gherkin-languages.json'
import Dialect from './Dialect'
import GherkinExe from './external/GherkinExe'
import { uuid, incrementing } from './IdGenerator'
import Gherkin from './Gherkin'
import IGherkinOptions from './IGherkinOptions'

export function fromStream(stream: Readable, options: IGherkinOptions = {}) {
return pipeline(
stream,
new BinaryToMessageStream(messages.Envelope.decodeDelimited),
new ParserMessageStream(options)
)
}

export function fromPaths(
paths: string[],
options: IGherkinOptions = {}
): Readable {
options = gherkinOptions(options)

if (process.env.GHERKIN_EXECUTABLE) {
return new GherkinExe(
process.env.GHERKIN_EXECUTABLE,
paths,
[],
options
).messageStream()
}

const combinedMessageStream = new PassThrough({
writableObjectMode: true,
readableObjectMode: true,
})

function pipeSequentially() {
const path = paths.shift()
if (path !== undefined) {
const parserMessageStream = new ParserMessageStream(options)
parserMessageStream.on('end', () => {
pipeSequentially()
})

const end = paths.length === 0
fs.createReadStream(path, { encoding: 'utf-8' })
.pipe(new SourceMessageStream(path))
.pipe(parserMessageStream)
.pipe(combinedMessageStream, { end })
}
}
pipeSequentially()
return combinedMessageStream
}

export function fromSources(
envelopes: messages.IEnvelope[],
options: IGherkinOptions = {}
): Readable {
options = gherkinOptions(options)
if (process.env.GHERKIN_EXECUTABLE) {
return new GherkinExe(
process.env.GHERKIN_EXECUTABLE,
[],
envelopes,
options
).messageStream()
}

const combinedMessageStream = new PassThrough({ objectMode: true })

function pipeSequentially() {
const envelope = envelopes.shift()
if (envelope !== undefined && envelope.source) {
const parserMessageStream = new ParserMessageStream(options)
parserMessageStream.pipe(combinedMessageStream, {
end: envelopes.length === 0,
})
parserMessageStream.on('end', pipeSequentially)
parserMessageStream.end(envelope)
}
}
pipeSequentially()

return combinedMessageStream
}

export function dialects(): { [key: string]: Dialect } {
return DIALECTS
}

export default {
fromStream,
fromPaths,
fromSources,
dialects,
uuid,
incrementing,
}
export default Gherkin
export { IGherkinOptions }
14 changes: 14 additions & 0 deletions src/makeGherkinOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { IdGenerator } from 'cucumber-messages'
import IGherkinOptions from './IGherkinOptions'

const defaultOptions: IGherkinOptions = {
defaultDialect: 'en',
includeSource: true,
includeGherkinDocument: true,
includePickles: true,
newId: IdGenerator.uuid(),
}

export default function gherkinOptions(options: IGherkinOptions) {
return { ...defaultOptions, ...options }
}
15 changes: 7 additions & 8 deletions src/pickles/compile.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { messages } from 'cucumber-messages'
import { messages, IdGenerator } from 'cucumber-messages'
import IGherkinDocument = messages.IGherkinDocument
import { NewId } from '../types'

export default function compile(
gherkinDocument: IGherkinDocument,
uri: string,
newId: NewId
newId: IdGenerator.NewId
) {
const pickles: messages.IPickle[] = []

Expand Down Expand Up @@ -63,7 +62,7 @@ function compileRule(
language: string,
pickles: messages.IPickle[],
uri: string,
newId: NewId
newId: IdGenerator.NewId
) {
let ruleBackgroundSteps = [].concat(featureBackgroundSteps)

Expand Down Expand Up @@ -103,7 +102,7 @@ function compileScenario(
language: string,
pickles: messages.IPickle[],
uri: string,
newId: NewId
newId: IdGenerator.NewId
) {
const steps =
scenario.steps.length === 0
Expand Down Expand Up @@ -133,7 +132,7 @@ function compileScenarioOutline(
language: string,
pickles: messages.IPickle[],
uri: string,
newId: NewId
newId: IdGenerator.NewId
) {
scenario.examples
.filter(e => e.tableHeader !== null)
Expand Down Expand Up @@ -234,7 +233,7 @@ function pickleSteps(
scenario: messages.GherkinDocument.Feature.IScenario,
variableCells: messages.GherkinDocument.Feature.TableRow.ITableCell[],
valuesRow: messages.GherkinDocument.Feature.ITableRow,
newId: NewId
newId: IdGenerator.NewId
) {
return scenario.steps.map(s => pickleStep(s, variableCells, valuesRow, newId))
}
Expand All @@ -243,7 +242,7 @@ function pickleStep(
step: messages.GherkinDocument.Feature.IStep,
variableCells: messages.GherkinDocument.Feature.TableRow.ITableCell[],
valuesRow: messages.GherkinDocument.Feature.ITableRow | null,
newId: NewId
newId: IdGenerator.NewId
) {
const astNodeIds = [step.id]
if (valuesRow) {
Expand Down
2 changes: 1 addition & 1 deletion src/stream/ParserMessageStream.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import generateMessages from './generateMessages'
import { Transform, TransformCallback } from 'stream'
import { IGherkinOptions } from '../types'
import { messages } from 'cucumber-messages'
import IGherkinOptions from '../IGherkinOptions'

/**
* Stream that reads Source messages and writes GherkinDocument and Pickle messages.
Expand Down
Loading

0 comments on commit e08cc10

Please sign in to comment.