Skip to content

Commit

Permalink
Merge pull request #2 from nigelng/feat/refactor-process-line
Browse files Browse the repository at this point in the history
refactor process line to cover with unit tests
  • Loading branch information
nigelng authored Jun 23, 2022
2 parents 71c47ba + 0e57340 commit cdd498a
Show file tree
Hide file tree
Showing 5 changed files with 1,106 additions and 796 deletions.
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,25 @@
},
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/core": "^7.17.10",
"@babel/node": "^7.17.10",
"@babel/preset-env": "^7.17.10",
"@babel/core": "^7.18.5",
"@babel/node": "^7.18.5",
"@babel/preset-env": "^7.18.2",
"@nigelng/eslint-config-base": "^1.0.0",
"@nigelng/prettier-config": "^1.0.0",
"babel-preset-minify": "^0.5.2",
"cross-env": "^7.0.3",
"eslint": "^8.15.0",
"husky": "^8.0.0",
"jest": "^28.1.0",
"lint-staged": "^12.4.1",
"eslint": "^8.18.0",
"husky": "^8.0.1",
"jest": "^28.1.1",
"lint-staged": "^13.0.2",
"nodemon": "^2.0.16",
"pinst": "^3.0.0",
"prettier": "^2.6.2",
"prettier": "^2.7.1",
"rimraf": "^3.0.2"
},
"dependencies": {
"pino": "^7.11.0",
"pino-pretty": "^7.6.1",
"pino": "^8.1.0",
"pino-pretty": "^8.1.0",
"ramda": "^0.28.0"
}
}
66 changes: 5 additions & 61 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,81 +1,25 @@
import { EOL } from 'node:os'
import path from 'path'

import { split, last, defaultTo, forEach, head } from 'ramda'
import { split, defaultTo, forEach, head } from 'ramda'

import { isNilOrEmpty, isOpeningTag, getClosingTag } from './helpers'
import logger from './logger'
import processLine from './processLine'

import CONSTANTS from 'consts'
import { readFile, getTags } from 'helpers'
import { readFile } from 'helpers'

const fileName = defaultTo(CONSTANTS.DEBUG_FILENAME, head(process.argv.slice(2)))
const datafilePath = path.resolve(__dirname, `../data/${fileName}`)

const processLineTags = (allTags) => {
const pendingOpeningTags = []
let loggedInvalidTag = false

forEach((tag) => {
/*
* This is an opening tag, so let's see what coming up next
*/
if (isOpeningTag(tag)) {
pendingOpeningTags.push(tag)
return
}

/*
* This tag is a closing tag:
* - if there is no previous opening tag, it's an orphaned closing tag
* - if matched with last opening tag, happy day
* - otherwise it is an unmatched closing tag
*/

const lastOpeningTag = last(pendingOpeningTags)

if (isNilOrEmpty(lastOpeningTag)) {
logger.info(`Expected # found ${tag}`)
loggedInvalidTag = true
return
}

const matchedClosingTag = getClosingTag(lastOpeningTag)

if (matchedClosingTag === tag) {
pendingOpeningTags.pop()
return
}

logger.info(`Expected ${matchedClosingTag} found ${tag}`)
loggedInvalidTag = true
}, allTags)

if (loggedInvalidTag) {
return
}

if (!isNilOrEmpty(pendingOpeningTags)) {
logger.info(`Expect ${getClosingTag(pendingOpeningTags[0])} found #`)
return
}

logger.info(`Correctly tagged paragraph`)
}

;(async () => {
try {
const text = defaultTo('', await readFile(datafilePath))
const lines = split(EOL, text)

forEach((line) => {
const allTags = getTags(line)

if (isNilOrEmpty(allTags)) {
return
}

processLineTags(allTags)
const result = processLine(line)
logger.info(result)
}, lines)
process.exit(0)
} catch {
Expand Down
60 changes: 60 additions & 0 deletions src/processLine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { last, forEach } from 'ramda'

import { isNilOrEmpty, isOpeningTag, getClosingTag, getTags } from './helpers'

export default (line) => {
const allTags = getTags(line)
let lineResult = ''

if (isNilOrEmpty(allTags)) {
return 'No tag found'
}

const pendingOpeningTags = []

forEach((tag) => {
// stop at the first unmatched tag
if (!isNilOrEmpty(lineResult)) {
return
}

if (isOpeningTag(tag)) {
/*
* This is an opening tag, so let's see what coming up next
*/
pendingOpeningTags.push(tag)
return
}

/*
* This tag is a closing tag:
* - if there is no previous opening tag, it's an orphaned closing tag
* - if it does not match last opening tag, it's an unmatched closing tag
* - otherwise happy day
*/

const lastOpeningTag = last(pendingOpeningTags)

if (isNilOrEmpty(lastOpeningTag)) {
lineResult = `Expected # found ${tag}`
return
}

const matchedClosingTag = getClosingTag(lastOpeningTag)

if (matchedClosingTag !== tag) {
lineResult = `Expected ${matchedClosingTag} found ${tag}`
return
}

pendingOpeningTags.pop()
}, allTags)

if (!isNilOrEmpty(lineResult)) {
return lineResult
}

return isNilOrEmpty(pendingOpeningTags)
? 'Correctly tagged paragraph'
: `Expect ${getClosingTag(pendingOpeningTags[0])} found #`
}
33 changes: 33 additions & 0 deletions tests/processLine.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import processLine from '../src/processLine'

describe('processLine', () => {
it('should return "No tag found" if the input line is empty', () => {
expect(processLine('')).toBe('No tag found')
expect(processLine()).toBe('No tag found')
})

it('should return "No tag found" if the input line contains no tag', () => {
expect(processLine('abc def xyz')).toBe('No tag found')
})

it('should return "Correctly tagged paragraph" if the input line contains valid matched tag', () => {
expect(processLine('<A> abc def xyz </A>')).toBe('Correctly tagged paragraph')
expect(processLine('<A><B><C> abc def xyz </C></B></A>')).toBe(
'Correctly tagged paragraph'
)
})

it('should return "Expected <tag> found #" if the input line contains orphaned opening tag', () => {
expect(processLine('<A> abc def xyz')).toBe('Expect </A> found #')
})

it('should return "Expected <tag> found <other-tag>" if the input line contains mismatched opening tag', () => {
expect(processLine('<A><B><C> abc def xyz </B></A>')).toBe(
'Expected </C> found </B>'
)
})

it('should return "Expected # found <tag>" if the input line contains orphaned closing tag', () => {
expect(processLine('abc def xyz</A>')).toBe('Expected # found </A>')
})
})
Loading

0 comments on commit cdd498a

Please sign in to comment.