wip
This commit is contained in:
@@ -6,49 +6,73 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
LexicalAnalyzer = require './lexical_analyzer'
|
LexicalAnalyzer = require './lexical_analyzer'
|
||||||
ParserState = require './parser_state'
|
ModPack = require '../game/mod_pack'
|
||||||
|
ParserData = require './parser_data'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
module.exports = class Parser
|
module.exports = class Parser
|
||||||
|
|
||||||
constructor: (state, fileName, rawText)->
|
constructor: (modPack, fileName, rawText)->
|
||||||
if not state? then throw new Error 'state is required'
|
|
||||||
|
|
||||||
@_extensions = []
|
@_extensions = []
|
||||||
@_fileName = fileName
|
@_fileName = fileName
|
||||||
@_lexer = new LexicalAnalyzer fileName, rawText
|
@_lexer = new LexicalAnalyzer fileName, rawText
|
||||||
@_state = state
|
@_modPack = new ModPack
|
||||||
|
@_data = new ParserData
|
||||||
|
|
||||||
|
modPackData = @_data.create {}, 'modPack'
|
||||||
|
modPackData.instance = @_modPack
|
||||||
|
|
||||||
@_loadSchema()
|
@_loadSchema()
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
# Public Methods ###############################################################################
|
||||||
|
|
||||||
processNextCommand: w.lift ->
|
next: ->
|
||||||
command = @_lexer.next()
|
if not @_lexer.isFinished
|
||||||
return unless command?
|
@_processNextCommand()
|
||||||
|
else if not @_data.isValidated
|
||||||
for extension in @_extensions
|
@_validateNextEntry()
|
||||||
continue unless extension.accepts command
|
else if not @_data.isBuilt
|
||||||
extension.execute command
|
@_buildNextEntry()
|
||||||
return
|
else if not @_data.isAssembled
|
||||||
|
@_assembleNextEntry()
|
||||||
throw new Error "unknown command: #{command.name}"
|
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
# Property Methods #############################################################################
|
||||||
|
|
||||||
getIsFinished: ->
|
getIsFinished: ->
|
||||||
return @_lexer.isFinished
|
return @_lexer.isFinished and @_data.isValidated and @_data.isBuilt and @_data.isAssembled
|
||||||
|
|
||||||
getState: ->
|
getData: ->
|
||||||
return @_state
|
return @_data
|
||||||
|
|
||||||
|
getModPack: ->
|
||||||
|
return @_modPack
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
Object.defineProperties @prototype,
|
||||||
|
data: { get:@::getData }
|
||||||
isFinished: { get:@::getIsFinished }
|
isFinished: { get:@::getIsFinished }
|
||||||
state: { get:@::getState }
|
modPack: { get:@::getModPack }
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
|
_assembleNextEntry: ->
|
||||||
|
entry = @_data.popNextToAssemble()
|
||||||
|
return unless entry?
|
||||||
|
|
||||||
|
for extensions in @_extensions
|
||||||
|
continue unless extension.canAssemble entry
|
||||||
|
extension.assemble entry
|
||||||
|
return
|
||||||
|
|
||||||
|
_buildNextEntry: ->
|
||||||
|
entry = @_data.popNextToBuild()
|
||||||
|
return unless entry?
|
||||||
|
|
||||||
|
for extensions in @_extensions
|
||||||
|
continue unless extension.canBuild entry
|
||||||
|
extension.build entry
|
||||||
|
return
|
||||||
|
|
||||||
_loadSchema: ->
|
_loadSchema: ->
|
||||||
command = @_lexer.next()
|
command = @_lexer.next()
|
||||||
if command.name isnt 'schema' then throw new Error "#{@_fileName} must start with the \"schema\" command"
|
if command.name isnt 'schema' then throw new Error "#{@_fileName} must start with the \"schema\" command"
|
||||||
@@ -56,11 +80,33 @@ module.exports = class Parser
|
|||||||
schema = command.argText
|
schema = command.argText
|
||||||
if schema is '1'
|
if schema is '1'
|
||||||
@_use new require './parser_extensions/current_pe_v1'
|
@_use new require './parser_extensions/current_pe_v1'
|
||||||
|
@_use new require './parser_extensions/item_pe_v1'
|
||||||
@_use new require './parser_extensions/mod_pe_v1'
|
@_use new require './parser_extensions/mod_pe_v1'
|
||||||
@_use new require './parser_extensions/mod_version_pe_v1'
|
@_use new require './parser_extensions/mod_version_pe_v1'
|
||||||
|
@_use new require './parser_extensions/recipe_pe_v1'
|
||||||
else
|
else
|
||||||
throw new Error "unknown schema version: #{schema}"
|
throw new Error "unknown schema version: #{schema}"
|
||||||
|
|
||||||
|
_processNextCommand: ->
|
||||||
|
command = @_lexer.next()
|
||||||
|
return unless command?
|
||||||
|
|
||||||
|
for extension in @_extensions
|
||||||
|
continue unless extension.canExecute command
|
||||||
|
extension.execute command
|
||||||
|
return
|
||||||
|
|
||||||
|
@_data.addError command, "unknown command: #{command.name}"
|
||||||
|
|
||||||
_use: (parserExtension)->
|
_use: (parserExtension)->
|
||||||
parserExtension.state = @_state
|
parserExtension.state = @_state
|
||||||
@_extensions.push parserExtension
|
@_extensions.push parserExtension
|
||||||
|
|
||||||
|
_validateNextEntry: ->
|
||||||
|
entry = @_data.popNextToValidate()
|
||||||
|
return unless entry?
|
||||||
|
|
||||||
|
for extensions in @_extensions
|
||||||
|
continue unless extension.canValidate entry
|
||||||
|
extension.validate entry
|
||||||
|
return
|
||||||
|
|||||||
+33
-16
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Crafting Guide - parser_state.coffee
|
# Crafting Guide - parser_data.coffee
|
||||||
#
|
#
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
# Copyright © 2014-2016 by Redwood Labs
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
@@ -7,11 +7,15 @@
|
|||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
module.exports = class ParserState
|
module.exports = class ParserData
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
@clear()
|
@clear()
|
||||||
|
|
||||||
|
@_toAssemble = []
|
||||||
|
@_toBuild = []
|
||||||
|
@_toValidate = []
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
# Public Methods ###############################################################################
|
||||||
|
|
||||||
addError: (command, message)->
|
addError: (command, message)->
|
||||||
@@ -24,6 +28,11 @@ module.exports = class ParserState
|
|||||||
|
|
||||||
typeData = @_findOrCreateType type
|
typeData = @_findOrCreateType type
|
||||||
itemData = @_current = typeData['current'] = typeData[id] = id:id, command:command, type:type
|
itemData = @_current = typeData['current'] = typeData[id] = id:id, command:command, type:type
|
||||||
|
|
||||||
|
@_toAssemble.push itemData
|
||||||
|
@_toBuild.push itemData
|
||||||
|
@_toValidate.push itemData
|
||||||
|
|
||||||
return itemData
|
return itemData
|
||||||
|
|
||||||
clear: ->
|
clear: ->
|
||||||
@@ -31,20 +40,6 @@ module.exports = class ParserState
|
|||||||
@_data = {}
|
@_data = {}
|
||||||
@_errors = []
|
@_errors = []
|
||||||
|
|
||||||
each: (callback)->
|
|
||||||
for type, typeData of @_data
|
|
||||||
for id, itemData of typeData
|
|
||||||
continue if id is 'current'
|
|
||||||
continue if id is 'type'
|
|
||||||
callback itemData
|
|
||||||
|
|
||||||
eachOfType: (type, callback)->
|
|
||||||
typeData = @_findOrCreateType type
|
|
||||||
for id, itemData of typeData
|
|
||||||
continue if id is 'current'
|
|
||||||
continue if id is 'type'
|
|
||||||
callback itemData
|
|
||||||
|
|
||||||
get: (type, id)->
|
get: (type, id)->
|
||||||
typeData = @_findOrCreateType type
|
typeData = @_findOrCreateType type
|
||||||
itemData = typeData[id] or null
|
itemData = typeData[id] or null
|
||||||
@@ -57,13 +52,35 @@ module.exports = class ParserState
|
|||||||
current = typeData['current'] or null
|
current = typeData['current'] or null
|
||||||
return current
|
return current
|
||||||
|
|
||||||
|
popNextToAssemble: ->
|
||||||
|
return @_toAssemble.pop() or null
|
||||||
|
|
||||||
|
popNextToBuild: ->
|
||||||
|
return @_toBuild.pop() or null
|
||||||
|
|
||||||
|
popNextToValidate: ->
|
||||||
|
return @_toValidate.pop() or null
|
||||||
|
|
||||||
# Property Methods #############################################################################
|
# Property Methods #############################################################################
|
||||||
|
|
||||||
getErrors: ->
|
getErrors: ->
|
||||||
return @_errors[..]
|
return @_errors[..]
|
||||||
|
|
||||||
|
getIsAssembled: ->
|
||||||
|
return @_toAssemble.length > 0
|
||||||
|
|
||||||
|
getIsBuilt: ->
|
||||||
|
return @_toBuild.length > 0
|
||||||
|
|
||||||
|
getIsValidated: ->
|
||||||
|
return @_toValidate.length > 0
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
Object.defineProperties @prototype,
|
||||||
errors: { get:@::getErrors }
|
errors: { get:@::getErrors }
|
||||||
|
isAssembled: { get:@::getIsAssembled }
|
||||||
|
isBuilt: { get:@::getIsBuilt }
|
||||||
|
isValidated: { get:@::getIsValidated }
|
||||||
|
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#
|
||||||
|
# Crafting Guide - parser_data.test.coffee
|
||||||
|
#
|
||||||
|
# Copyright © 2014-2016 by Redwood Labs
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
ParserCommand = require './parser_command'
|
||||||
|
ParserData = require './parser_data'
|
||||||
|
|
||||||
|
########################################################################################################################
|
||||||
|
|
||||||
|
command = state = null
|
||||||
|
|
||||||
|
########################################################################################################################
|
||||||
|
|
||||||
|
describe 'parser_data.coffee', ->
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
state = new ParserData
|
||||||
|
command = new ParserCommand name:'alpha', fileName:'file.cg', lineNumber:1
|
||||||
|
|
||||||
|
describe 'create', ->
|
||||||
|
|
||||||
|
it 'returns an object with the given id', ->
|
||||||
|
alpha = state.create command, 'alpha', 0
|
||||||
|
alpha.id.should.equal 0
|
||||||
|
alpha.command.location.should.equal 'file.cg:1'
|
||||||
|
|
||||||
|
it 'returns an object with a newly created id when none is given', ->
|
||||||
|
alpha = state.create command, 'alpha'
|
||||||
|
alpha.id.should.not.be.null
|
||||||
|
alpha.id.should.match /^alpha-[0-9]+$/
|
||||||
|
alpha.command.location.should.equal 'file.cg:1'
|
||||||
|
|
||||||
|
describe 'get', ->
|
||||||
|
|
||||||
|
it 'returns a previously created item', ->
|
||||||
|
alpha1 = state.create command, 'alpha', 0
|
||||||
|
alpha2 = state.get 'alpha', 0
|
||||||
|
alpha1.should.equal alpha2
|
||||||
|
|
||||||
|
it 'returns null when no such item exists', ->
|
||||||
|
alpha = state.create command, 'alpha', 0
|
||||||
|
expect(state.get 'alpha', 1).to.be.null
|
||||||
|
expect(state.get 'bravo', 0).to.be.null
|
||||||
|
|
||||||
|
describe 'getCurrent', ->
|
||||||
|
|
||||||
|
it 'returns the new item each time one is created', ->
|
||||||
|
alpha1 = state.create command, 'alpha', 0
|
||||||
|
state.getCurrent('alpha').id.should.equal 0
|
||||||
|
|
||||||
|
alpha2 = state.create command, 'alpha', 1
|
||||||
|
state.getCurrent('alpha').id.should.equal 1
|
||||||
@@ -9,55 +9,77 @@
|
|||||||
|
|
||||||
module.exports = class ParserExtension
|
module.exports = class ParserExtension
|
||||||
|
|
||||||
constructor: (state)->
|
constructor: (data, type, commandFunctions)->
|
||||||
@state = state
|
@data = data
|
||||||
|
|
||||||
|
@_commandFunctions = commandFunctions or {}
|
||||||
|
@_type = type or null
|
||||||
|
|
||||||
# Public Methods ###############################################################################
|
# Public Methods ###############################################################################
|
||||||
|
|
||||||
accepts: (command)->
|
canAssemble: (entry)->
|
||||||
return @_findCommandMethod(command)?
|
return entry.type is @_type
|
||||||
|
|
||||||
execute: w.lift (command)->
|
canBuild: (entry)->
|
||||||
if not @_state? then throw new Error '@state must be defined before executing commands'
|
return entry.type is @_type
|
||||||
|
|
||||||
method = @_findCommandMethod command
|
canExecute: (command)->
|
||||||
method.call this, command
|
_.isFunction @_commandFunctions[command.name]
|
||||||
|
|
||||||
|
canValidate: (entry)->
|
||||||
|
return entry.type is @_type
|
||||||
|
|
||||||
|
execute: (command)->
|
||||||
|
if not @_data? then throw new Error '@data must be defined before executing commands'
|
||||||
|
|
||||||
|
func = @_commandFunctions[command.name]
|
||||||
|
if not func then throw new Error "#{@constructor.name} cannot handle command: #{command.name}"
|
||||||
|
|
||||||
|
func.call this, command
|
||||||
|
return this
|
||||||
|
|
||||||
# Error Checking Helpers #######################################################################
|
# Error Checking Helpers #######################################################################
|
||||||
|
|
||||||
alreadyExists: (command, type, id)->
|
alreadyExists: (command, type, id)->
|
||||||
obj = @state.get(type, id)
|
obj = @data.get(type, id)
|
||||||
if obj?
|
if obj?
|
||||||
@state.addError command, "a #{type} called #{id} has already been declared"
|
@data.addError command, "a #{type} called #{id} has already been declared"
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
duplicateField: (command, obj, field)->
|
duplicateField: (command, obj, field)->
|
||||||
if obj[field]?
|
if obj[field]?
|
||||||
@state.addError command, "duplicate #{field}"
|
@data.addError command, "duplicate #{field}"
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
missingCurrent: (command, type)->
|
missingCurrent: (command, type)->
|
||||||
obj = @state.getCurrent type
|
obj = @data.getCurrent type
|
||||||
if not obj?
|
if not obj?
|
||||||
@state.addError command, "you must declare a #{type} before using #{command.name}"
|
@data.addError command, "you must declare a #{type} before using #{command.name}"
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
missingArgs: (command)->
|
missingArgs: (command)->
|
||||||
if not command.args or command.args.length is 0
|
if not command.args or command.args.length is 0
|
||||||
@state.addError command, "#{command.name} requires at least one item"
|
@data.addError command, "#{command.name} requires at least one item"
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
missingArgText: (command)->
|
missingArgText: (command)->
|
||||||
if command.argText.length is 0
|
if command.argText.length is 0
|
||||||
@state.addError command, "#{command.name} cannot be empty"
|
@data.addError command, "#{command.name} cannot be empty"
|
||||||
|
return true
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
tooFewArguments: (command, minimum)->
|
||||||
|
if command.args.length < minimum
|
||||||
|
@data.addError command, "#{command.name} requires at least #{minimum} arguments"
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -71,7 +93,7 @@ module.exports = class ParserExtension
|
|||||||
when "yes" then return true
|
when "yes" then return true
|
||||||
when "no" then return false
|
when "no" then return false
|
||||||
|
|
||||||
@state.addError command, "#{command.name} requires \"yes\" or \"no\""
|
@data.addError command, "#{command.name} requires \"yes\" or \"no\""
|
||||||
return null
|
return null
|
||||||
|
|
||||||
parseInt: (command, text)->
|
parseInt: (command, text)->
|
||||||
@@ -86,20 +108,43 @@ module.exports = class ParserExtension
|
|||||||
|
|
||||||
# Property Methods #############################################################################
|
# Property Methods #############################################################################
|
||||||
|
|
||||||
getState: ->
|
getData: ->
|
||||||
return @_state
|
return @_data
|
||||||
|
|
||||||
setState: (state)->
|
setData: (data)->
|
||||||
if not state? then throw new Error 'state cannot be undefined'
|
if not data? then throw new Error 'data cannot be undefined'
|
||||||
@_state = state
|
@_data = data
|
||||||
|
|
||||||
Object.defineProperties @prototype,
|
Object.defineProperties @prototype,
|
||||||
state: { get:@::getState, set:@::setState }
|
data: { get:@::getData, set:@::setData }
|
||||||
|
|
||||||
|
# Overridable Methods ##########################################################################
|
||||||
|
|
||||||
|
assmeble: (entry)->
|
||||||
|
throw new Error "#{@constructor.name} must override the `assemble` method"
|
||||||
|
|
||||||
|
build: (entry)->
|
||||||
|
throw new Error "#{@constructor.name} must override the `build` method"
|
||||||
|
|
||||||
|
validate: (entry)->
|
||||||
|
throw new Error "#{@constructor.name} must override the `validate` method"
|
||||||
|
|
||||||
# Private Methods ##############################################################################
|
# Private Methods ##############################################################################
|
||||||
|
|
||||||
|
_findBuildMethod: (entry)->
|
||||||
|
methodName = "_build_#{entry.type}"
|
||||||
|
method = this[methodName]
|
||||||
|
return null unless _.isFunction method
|
||||||
|
return method
|
||||||
|
|
||||||
_findCommandMethod: (command)->
|
_findCommandMethod: (command)->
|
||||||
methodName = "_command_#{command.name}"
|
methodName = "_command_#{command.name}"
|
||||||
method = this[methodName]
|
method = this[methodName]
|
||||||
return null unless _.isFunction(method)
|
return null unless _.isFunction method
|
||||||
|
return method
|
||||||
|
|
||||||
|
_findValidateMethod: (command)->
|
||||||
|
methodName = "_validate_#{command.name}"
|
||||||
|
method = this[methodName]
|
||||||
|
return null unless _.isFunction method
|
||||||
return method
|
return method
|
||||||
|
|||||||
@@ -11,24 +11,30 @@ ParserExtension = require '../parser_extension'
|
|||||||
|
|
||||||
module.exports = class CurrentParserExtensionV1 extends ParserExtension
|
module.exports = class CurrentParserExtensionV1 extends ParserExtension
|
||||||
|
|
||||||
|
constructor: (data)->
|
||||||
|
super data, null,
|
||||||
|
documentationUrl: @_command_documentationUrl
|
||||||
|
description: @_command_description
|
||||||
|
name: @_command_name
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
# Command Methods ##############################################################################
|
||||||
|
|
||||||
_command_documentationUrl: (command)->
|
_command_documentationUrl: (command)->
|
||||||
current = @state.getCurrent()
|
current = @data.getCurrent()
|
||||||
return if @duplicateField command, current, 'documentationUrl'
|
return if @duplicateField command, current, 'documentationUrl'
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
|
|
||||||
current.documentationUrl = command.argText
|
current.documentationUrl = command.argText
|
||||||
|
|
||||||
_command_description: (command)->
|
_command_description: (command)->
|
||||||
current = @state.getCurrent()
|
current = @data.getCurrent()
|
||||||
return if @duplicateField command, current, 'description'
|
return if @duplicateField command, current, 'description'
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
|
|
||||||
current.description = command.argText
|
current.description = command.argText
|
||||||
|
|
||||||
_command_name: (command)->
|
_command_name: (command)->
|
||||||
current = @state.getCurrent()
|
current = @data.getCurrent()
|
||||||
return if @duplicateField command, current, 'name'
|
return if @duplicateField command, current, 'name'
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
CurrentParserExtensionV1 = require './current_pe_v1'
|
CurrentParserExtensionV1 = require './current_pe_v1'
|
||||||
ParserState = require '../parser_state'
|
ParserData = require '../parser_data'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ parser = state = null
|
|||||||
describe 'current_pe_v1.coffee', ->
|
describe 'current_pe_v1.coffee', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
state = new ParserState
|
state = new ParserData
|
||||||
parser = new CurrentParserExtensionV1 state
|
parser = new CurrentParserExtensionV1 state
|
||||||
|
|
||||||
state.create {}, 'alpha'
|
state.create {}, 'alpha'
|
||||||
@@ -26,7 +26,6 @@ describe 'current_pe_v1.coffee', ->
|
|||||||
|
|
||||||
it 'assigns to the current object', ->
|
it 'assigns to the current object', ->
|
||||||
parser.execute name:'documentationUrl', argText:'bravo'
|
parser.execute name:'documentationUrl', argText:'bravo'
|
||||||
.then ->
|
|
||||||
state.getCurrent().documentationUrl.should.equal 'bravo'
|
state.getCurrent().documentationUrl.should.equal 'bravo'
|
||||||
state.errors.should.eql []
|
state.errors.should.eql []
|
||||||
|
|
||||||
@@ -34,7 +33,6 @@ describe 'current_pe_v1.coffee', ->
|
|||||||
|
|
||||||
it 'assigns to the current object', ->
|
it 'assigns to the current object', ->
|
||||||
parser.execute name:'description', argText:'bravo'
|
parser.execute name:'description', argText:'bravo'
|
||||||
.then ->
|
|
||||||
state.getCurrent().description.should.equal 'bravo'
|
state.getCurrent().description.should.equal 'bravo'
|
||||||
state.errors.should.eql []
|
state.errors.should.eql []
|
||||||
|
|
||||||
@@ -42,6 +40,5 @@ describe 'current_pe_v1.coffee', ->
|
|||||||
|
|
||||||
it 'assigns to the current object', ->
|
it 'assigns to the current object', ->
|
||||||
parser.execute name:'name', argText:'bravo'
|
parser.execute name:'name', argText:'bravo'
|
||||||
.then ->
|
|
||||||
state.getCurrent().name.should.equal 'bravo'
|
state.getCurrent().name.should.equal 'bravo'
|
||||||
state.errors.should.eql []
|
state.errors.should.eql []
|
||||||
|
|||||||
@@ -11,6 +11,22 @@ ParserExtension = require '../parser_extension'
|
|||||||
|
|
||||||
module.exports = class ItemParserExtensionV1 extends ParserExtension
|
module.exports = class ItemParserExtensionV1 extends ParserExtension
|
||||||
|
|
||||||
|
constructor: (data)->
|
||||||
|
super data, 'item',
|
||||||
|
gatherable: @_command_gatherable
|
||||||
|
item: @_command_item
|
||||||
|
|
||||||
|
# ParserExtensions Overrides ###################################################################
|
||||||
|
|
||||||
|
assmeble: (entry)->
|
||||||
|
throw new Error "#{@constructor.name} must override the `assemble` method"
|
||||||
|
|
||||||
|
build: (entry)->
|
||||||
|
entry.instance = new
|
||||||
|
throw new Error "#{@constructor.name} must override the `build` method"
|
||||||
|
|
||||||
|
validate: (entry)-> # do nothing
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
# Command Methods ##############################################################################
|
||||||
|
|
||||||
_command_gatherable: (command)->
|
_command_gatherable: (command)->
|
||||||
@@ -18,7 +34,7 @@ module.exports = class ItemParserExtensionV1 extends ParserExtension
|
|||||||
|
|
||||||
return if @missingCurrent command, 'item'
|
return if @missingCurrent command, 'item'
|
||||||
|
|
||||||
item = @state.getCurrent 'item'
|
item = @data.getCurrent 'item'
|
||||||
return if @duplicateField command, 'gatherable', item
|
return if @duplicateField command, 'gatherable', item
|
||||||
|
|
||||||
gatherable = @parseBoolean command, command.argText
|
gatherable = @parseBoolean command, command.argText
|
||||||
@@ -31,10 +47,19 @@ module.exports = class ItemParserExtensionV1 extends ParserExtension
|
|||||||
return if @missingCurrent command, 'modVersion'
|
return if @missingCurrent command, 'modVersion'
|
||||||
return if @alreadyExists command, 'item', command.argText
|
return if @alreadyExists command, 'item', command.argText
|
||||||
|
|
||||||
item = @state.create command, 'item', command.argText
|
item = @data.create command, 'item', command.argText
|
||||||
item.name = command.argText
|
item.name = command.argText
|
||||||
|
|
||||||
group = @state.getCurrent 'itemGroup'
|
group = @data.getCurrent 'itemGroup'
|
||||||
if group? then item.group = group
|
if group? then item.group = group
|
||||||
|
|
||||||
item.modVersion = @state.getCurrent 'modVersion'
|
item.modVersion = @data.getCurrent 'modVersion'
|
||||||
|
|
||||||
|
_command_video: (command)->
|
||||||
|
return if @missingArgs command
|
||||||
|
return if @missingCurrent command, 'item'
|
||||||
|
return if @tooFewArguments command, 2
|
||||||
|
|
||||||
|
item = @data.getCurrent 'item'
|
||||||
|
item.videos ?= []
|
||||||
|
item.videos.push youTubeId:command.args[0], caption:command.args[1..].join(', ')
|
||||||
|
|||||||
@@ -6,40 +6,38 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
ItemParserExtensionV1 = require './item_pe_v1'
|
ItemParserExtensionV1 = require './item_pe_v1'
|
||||||
ParserState = require '../parser_state'
|
ParserData = require '../parser_data'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
parser = state = null
|
parser = data = null
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
describe 'item_pe_v1.coffee', ->
|
describe 'item_pe_v1.coffee', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
state = new ParserState
|
data = new ParserData
|
||||||
parser = new ItemParserExtensionV1 state
|
parser = new ItemParserExtensionV1 data
|
||||||
|
|
||||||
state.create {}, 'modVersion', 0
|
data.create {}, 'modVersion', 0
|
||||||
|
|
||||||
describe 'gatherable', ->
|
describe 'gatherable', ->
|
||||||
|
|
||||||
it 'assigns to the current item', ->
|
it 'assigns to the current item', ->
|
||||||
state.create {}, 'item', 1
|
data.create {}, 'item', 1
|
||||||
|
|
||||||
parser.execute name:'gatherable', argText:'yes'
|
parser.execute name:'gatherable', argText:'yes'
|
||||||
.then ->
|
data.getCurrent('item').gatherable.should.be.true
|
||||||
state.getCurrent('item').gatherable.should.be.true
|
data.errors.should.eql []
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'item', ->
|
describe 'item', ->
|
||||||
|
|
||||||
it 'creates a new item', ->
|
it 'creates a new item', ->
|
||||||
state.create {}, 'itemGroup', 2
|
data.create {}, 'itemGroup', 2
|
||||||
|
|
||||||
parser.execute name:'item', argText:'alpha'
|
parser.execute name:'item', argText:'alpha'
|
||||||
.then ->
|
item = data.getCurrent 'item'
|
||||||
item = state.getCurrent 'item'
|
|
||||||
item.id.should.equal 'alpha'
|
item.id.should.equal 'alpha'
|
||||||
item.name.should.equal 'alpha'
|
item.name.should.equal 'alpha'
|
||||||
item.modVersion.id.should.equal 0
|
item.modVersion.id.should.equal 0
|
||||||
|
|||||||
@@ -11,12 +11,19 @@ ParserExtension = require '../parser_extension'
|
|||||||
|
|
||||||
module.exports = class ModParserExtensionV1 extends ParserExtension
|
module.exports = class ModParserExtensionV1 extends ParserExtension
|
||||||
|
|
||||||
|
constructor: (data)->
|
||||||
|
super data, 'mod',
|
||||||
|
author: @_command_author
|
||||||
|
downloadUrl: @_command_downloadUrl
|
||||||
|
homePageUrl: @_command_homePageUrl
|
||||||
|
mod: @_command_mod
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
# Command Methods ##############################################################################
|
||||||
|
|
||||||
_command_author: (command)->
|
_command_author: (command)->
|
||||||
return if @missingCurrent command, 'mod'
|
return if @missingCurrent command, 'mod'
|
||||||
|
|
||||||
mod = @state.getCurrent 'mod'
|
mod = @data.getCurrent 'mod'
|
||||||
return if @duplicateField command, mod, 'author'
|
return if @duplicateField command, mod, 'author'
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
|
|
||||||
@@ -25,7 +32,7 @@ module.exports = class ModParserExtensionV1 extends ParserExtension
|
|||||||
_command_downloadUrl: (command)->
|
_command_downloadUrl: (command)->
|
||||||
return if @missingCurrent command, 'mod'
|
return if @missingCurrent command, 'mod'
|
||||||
|
|
||||||
mod = @state.getCurrent 'mod'
|
mod = @data.getCurrent 'mod'
|
||||||
return if @duplicateField command, mod, 'downloadUrl'
|
return if @duplicateField command, mod, 'downloadUrl'
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
|
|
||||||
@@ -34,7 +41,7 @@ module.exports = class ModParserExtensionV1 extends ParserExtension
|
|||||||
_command_homePageUrl: (command)->
|
_command_homePageUrl: (command)->
|
||||||
return if @missingCurrent command, 'mod'
|
return if @missingCurrent command, 'mod'
|
||||||
|
|
||||||
mod = @state.getCurrent 'mod'
|
mod = @data.getCurrent 'mod'
|
||||||
return if @duplicateField command, mod, 'homePageUrl'
|
return if @duplicateField command, mod, 'homePageUrl'
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
|
|
||||||
@@ -44,4 +51,4 @@ module.exports = class ModParserExtensionV1 extends ParserExtension
|
|||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
return if @alreadyExists command, 'mod', command.argText
|
return if @alreadyExists command, 'mod', command.argText
|
||||||
|
|
||||||
@state.create command, 'mod', command.argText
|
@data.create command, 'mod', command.argText
|
||||||
|
|||||||
@@ -6,50 +6,46 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
ModParserExtensionV1 = require './mod_pe_v1'
|
ModParserExtensionV1 = require './mod_pe_v1'
|
||||||
ParserState = require '../parser_state'
|
ParserData = require '../parser_data'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
parser = state = null
|
parser = data = null
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
describe 'mod_pe_v1.coffee', ->
|
describe 'mod_pe_v1.coffee', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
state = new ParserState
|
data = new ParserData
|
||||||
parser = new ModParserExtensionV1 state
|
parser = new ModParserExtensionV1 data
|
||||||
|
|
||||||
state.create {}, 'mod', 0
|
data.create {}, 'mod', 0
|
||||||
|
|
||||||
describe 'author', ->
|
describe 'author', ->
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
it 'assigns to the current mod', ->
|
||||||
parser.execute name:'author', argText:'alpha'
|
parser.execute name:'author', argText:'alpha'
|
||||||
.then ->
|
data.getCurrent('mod').author.should.equal 'alpha'
|
||||||
state.getCurrent('mod').author.should.equal 'alpha'
|
data.errors.should.eql []
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'downloadUrl', ->
|
describe 'downloadUrl', ->
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
it 'assigns to the current mod', ->
|
||||||
parser.execute name:'downloadUrl', argText:'alpha'
|
parser.execute name:'downloadUrl', argText:'alpha'
|
||||||
.then ->
|
data.getCurrent('mod').downloadUrl.should.equal 'alpha'
|
||||||
state.getCurrent('mod').downloadUrl.should.equal 'alpha'
|
data.errors.should.eql []
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'homePageUrl', ->
|
describe 'homePageUrl', ->
|
||||||
|
|
||||||
it 'assigns to the current mod', ->
|
it 'assigns to the current mod', ->
|
||||||
parser.execute name:'homePageUrl', argText:'alpha'
|
parser.execute name:'homePageUrl', argText:'alpha'
|
||||||
.then ->
|
data.getCurrent('mod').homePageUrl.should.equal 'alpha'
|
||||||
state.getCurrent('mod').homePageUrl.should.equal 'alpha'
|
data.errors.should.eql []
|
||||||
state.errors.should.eql []
|
|
||||||
|
|
||||||
describe 'mod', ->
|
describe 'mod', ->
|
||||||
|
|
||||||
it 'creates a new mod', ->
|
it 'creates a new mod', ->
|
||||||
parser.execute name:'mod', argText:'alpha'
|
parser.execute name:'mod', argText:'alpha'
|
||||||
.then ->
|
mod = data.getCurrent 'mod'
|
||||||
mod = state.getCurrent 'mod'
|
|
||||||
mod.id.should.equal 'alpha'
|
mod.id.should.equal 'alpha'
|
||||||
|
|||||||
@@ -11,18 +11,23 @@ ParserExtension = require '../parser_extension'
|
|||||||
|
|
||||||
module.exports = class ModVersionParserExtensionV1 extends ParserExtension
|
module.exports = class ModVersionParserExtensionV1 extends ParserExtension
|
||||||
|
|
||||||
|
constructor: (data)->
|
||||||
|
super data, 'modVersion',
|
||||||
|
group: @_command_group
|
||||||
|
version: @_command_version
|
||||||
|
|
||||||
# Command Methods ##############################################################################
|
# Command Methods ##############################################################################
|
||||||
|
|
||||||
_command_group: (command)->
|
_command_group: (command)->
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
return if @missingCurrent command, 'modVersion'
|
return if @missingCurrent command, 'modVersion'
|
||||||
|
|
||||||
group = @state.create command, 'itemGroup', command.argText
|
group = @data.create command, 'itemGroup', command.argText
|
||||||
group.modVersion = @state.getCurrent 'modVersion'
|
group.modVersion = @data.getCurrent 'modVersion'
|
||||||
|
|
||||||
_command_version: (command)->
|
_command_version: (command)->
|
||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
return if @missingCurrent command, 'mod'
|
return if @missingCurrent command, 'mod'
|
||||||
|
|
||||||
modVersion = @state.create command, 'modVersion', command.argText
|
modVersion = @data.create command, 'modVersion', command.argText
|
||||||
modVersion.mod = @state.getCurrent 'mod'
|
modVersion.mod = @data.getCurrent 'mod'
|
||||||
|
|||||||
@@ -6,30 +6,29 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
ModVersionParserExtensionV1 = require './mod_version_pe_v1'
|
ModVersionParserExtensionV1 = require './mod_version_pe_v1'
|
||||||
ParserState = require '../parser_state'
|
ParserData = require '../parser_data'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
parser = state = null
|
parser = data = null
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
describe 'mod_version_pe_v1.coffee', ->
|
describe 'mod_version_pe_v1.coffee', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
state = new ParserState
|
data = new ParserData
|
||||||
parser = new ModVersionParserExtensionV1 state
|
parser = new ModVersionParserExtensionV1 data
|
||||||
|
|
||||||
state.create {}, 'mod', 0
|
data.create {}, 'mod', 0
|
||||||
|
|
||||||
describe 'group', ->
|
describe 'group', ->
|
||||||
|
|
||||||
it 'creates a new item group', ->
|
it 'creates a new item group', ->
|
||||||
state.create {}, 'modVersion', 1
|
data.create {}, 'modVersion', 1
|
||||||
|
|
||||||
parser.execute name:'group', argText:'alpha'
|
parser.execute name:'group', argText:'alpha'
|
||||||
.then ->
|
itemGroup = data.getCurrent('itemGroup')
|
||||||
itemGroup = state.getCurrent('itemGroup')
|
|
||||||
itemGroup.id.should.equal 'alpha'
|
itemGroup.id.should.equal 'alpha'
|
||||||
itemGroup.modVersion.id.should.equal 1
|
itemGroup.modVersion.id.should.equal 1
|
||||||
|
|
||||||
@@ -37,7 +36,6 @@ describe 'mod_version_pe_v1.coffee', ->
|
|||||||
|
|
||||||
it 'creates a new mod version', ->
|
it 'creates a new mod version', ->
|
||||||
parser.execute name:'version', argText:'alpha'
|
parser.execute name:'version', argText:'alpha'
|
||||||
.then ->
|
modVersion = data.getCurrent 'modVersion'
|
||||||
modVersion = state.getCurrent 'modVersion'
|
|
||||||
modVersion.id.should.equal 'alpha'
|
modVersion.id.should.equal 'alpha'
|
||||||
modVersion.mod.id.should.equal 0
|
modVersion.mod.id.should.equal 0
|
||||||
|
|||||||
@@ -11,6 +11,17 @@ ParserExtension = require '../parser_extension'
|
|||||||
|
|
||||||
module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
||||||
|
|
||||||
|
constructor: (data)->
|
||||||
|
super data, 'recipe',
|
||||||
|
extras: @_command_extras
|
||||||
|
input: @_command_input
|
||||||
|
pattern: @_command_pattern
|
||||||
|
recipe: @_command_recipe
|
||||||
|
quantity: @_command_quantity
|
||||||
|
tools: @_command_tools
|
||||||
|
|
||||||
|
# Class Methods ################################################################################
|
||||||
|
|
||||||
@::PATTERN = /[0-9. ]+/
|
@::PATTERN = /[0-9. ]+/
|
||||||
|
|
||||||
@::STACK = /^([0-9]+) +(.+)$/
|
@::STACK = /^([0-9]+) +(.+)$/
|
||||||
@@ -20,7 +31,7 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
invalidPattern: (command)->
|
invalidPattern: (command)->
|
||||||
match = command.argText.match @PATTERN
|
match = command.argText.match @PATTERN
|
||||||
if not match?
|
if not match?
|
||||||
@state.addError command, "invalid pattern: \"#{command.argText}\""
|
@data.addError command, "invalid pattern: \"#{command.argText}\""
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return false
|
return false
|
||||||
@@ -31,7 +42,7 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
return if @missingCurrent command, 'recipe'
|
return if @missingCurrent command, 'recipe'
|
||||||
return if @missingArgs command
|
return if @missingArgs command
|
||||||
|
|
||||||
recipe = @state.getCurrent 'recipe'
|
recipe = @data.getCurrent 'recipe'
|
||||||
return if @duplicateField command, 'extras', recipe
|
return if @duplicateField command, 'extras', recipe
|
||||||
|
|
||||||
recipe.extras = command.args
|
recipe.extras = command.args
|
||||||
@@ -40,7 +51,7 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
return if @missingCurrent command, 'recipe'
|
return if @missingCurrent command, 'recipe'
|
||||||
return if @missingArgs command
|
return if @missingArgs command
|
||||||
|
|
||||||
recipe = @state.getCurrent 'recipe'
|
recipe = @data.getCurrent 'recipe'
|
||||||
return if @duplicateField command, 'input', recipe
|
return if @duplicateField command, 'input', recipe
|
||||||
|
|
||||||
recipe.input = (@_parseStack(arg) for arg in command.args)
|
recipe.input = (@_parseStack(arg) for arg in command.args)
|
||||||
@@ -50,7 +61,7 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
return if @missingArgText command
|
return if @missingArgText command
|
||||||
return if @invalidPattern command
|
return if @invalidPattern command
|
||||||
|
|
||||||
recipe = @state.getCurrent 'recipe'
|
recipe = @data.getCurrent 'recipe'
|
||||||
return if @duplicateField command, 'pattern', recipe
|
return if @duplicateField command, 'pattern', recipe
|
||||||
|
|
||||||
recipe.pattern = command.argText
|
recipe.pattern = command.argText
|
||||||
@@ -58,8 +69,8 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
_command_recipe: (command)->
|
_command_recipe: (command)->
|
||||||
return if @missingCurrent command, 'item'
|
return if @missingCurrent command, 'item'
|
||||||
|
|
||||||
recipe = @state.create command, 'recipe'
|
recipe = @data.create command, 'recipe'
|
||||||
recipe.item = @state.getCurrent 'item'
|
recipe.item = @data.getCurrent 'item'
|
||||||
|
|
||||||
_command_quantity: (command)->
|
_command_quantity: (command)->
|
||||||
return if @missingCurrent command, 'recipe'
|
return if @missingCurrent command, 'recipe'
|
||||||
@@ -68,7 +79,7 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
value = @parseInt command, command.argText
|
value = @parseInt command, command.argText
|
||||||
return unless value?
|
return unless value?
|
||||||
|
|
||||||
recipe = @state.getCurrent 'recipe'
|
recipe = @data.getCurrent 'recipe'
|
||||||
return if @duplicateField command, 'quantity', recipe
|
return if @duplicateField command, 'quantity', recipe
|
||||||
|
|
||||||
recipe.quantity = value
|
recipe.quantity = value
|
||||||
@@ -77,7 +88,7 @@ module.exports = class RecipeParserExtensionV1 extends ParserExtension
|
|||||||
return if @missingCurrent command, 'recipe'
|
return if @missingCurrent command, 'recipe'
|
||||||
return if @missingArgs command
|
return if @missingArgs command
|
||||||
|
|
||||||
recipe = @state.getCurrent 'recipe'
|
recipe = @data.getCurrent 'recipe'
|
||||||
return if @duplicateField command, 'tools', recipe
|
return if @duplicateField command, 'tools', recipe
|
||||||
|
|
||||||
recipe.tools = (@_parseStack(arg) for arg in command.args)
|
recipe.tools = (@_parseStack(arg) for arg in command.args)
|
||||||
|
|||||||
@@ -6,109 +6,100 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
RecipeParserExtensionV1 = require './recipe_pe_v1'
|
RecipeParserExtensionV1 = require './recipe_pe_v1'
|
||||||
ParserState = require '../parser_state'
|
ParserData = require '../parser_data'
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
parser = state = null
|
parser = data = null
|
||||||
|
|
||||||
########################################################################################################################
|
########################################################################################################################
|
||||||
|
|
||||||
describe 'recipe_pe_v1.coffee', ->
|
describe 'recipe_pe_v1.coffee', ->
|
||||||
|
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
state = new ParserState
|
data = new ParserData
|
||||||
parser = new RecipeParserExtensionV1 state
|
parser = new RecipeParserExtensionV1 data
|
||||||
|
|
||||||
state.create {}, 'item', 0
|
data.create {}, 'item', 0
|
||||||
|
|
||||||
describe 'extras', ->
|
describe 'extras', ->
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
it 'assigns to the current recipe', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'extras', args:['bravo']
|
parser.execute name:'extras', args:['bravo']
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.extras.should.eql ['bravo']
|
recipe.extras.should.eql ['bravo']
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
describe 'input', ->
|
describe 'input', ->
|
||||||
|
|
||||||
it 'correctly reads a single item', ->
|
it 'correctly reads a single item', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'input', args:['bravo']
|
parser.execute name:'input', args:['bravo']
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.input.should.eql [name:'bravo', quantity:1]
|
recipe.input.should.eql [name:'bravo', quantity:1]
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
it 'correctly reads multiple items', ->
|
it 'correctly reads multiple items', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'input', args:['bravo', 'charlie']
|
parser.execute name:'input', args:['bravo', 'charlie']
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.input.should.eql [{name:'bravo', quantity:1}, {name:'charlie', quantity:1}]
|
recipe.input.should.eql [{name:'bravo', quantity:1}, {name:'charlie', quantity:1}]
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
it 'correctly reads a stack', ->
|
it 'correctly reads a stack', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'input', args:['10 bravo']
|
parser.execute name:'input', args:['10 bravo']
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.input.should.eql [name:'bravo', quantity:10]
|
recipe.input.should.eql [name:'bravo', quantity:10]
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
describe 'pattern', ->
|
describe 'pattern', ->
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
it 'assigns to the current recipe', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'pattern', argText:'00. 00. ...'
|
parser.execute name:'pattern', argText:'00. 00. ...'
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.pattern.should.equal '00. 00. ...'
|
recipe.pattern.should.equal '00. 00. ...'
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
it 'rejects an invalid pattern', ->
|
it 'rejects an invalid pattern', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'pattern', argText:'alpha'
|
parser.execute name:'pattern', argText:'alpha'
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
expect(recipe.pattern).to.be.undefined
|
expect(recipe.pattern).to.be.undefined
|
||||||
(e.message for e in state.errors).should.eql ['invalid pattern: "alpha"']
|
(e.message for e in data.errors).should.eql ['invalid pattern: "alpha"']
|
||||||
|
|
||||||
describe 'recipe', ->
|
describe 'recipe', ->
|
||||||
|
|
||||||
it 'creates a new recipe', ->
|
it 'creates a new recipe', ->
|
||||||
parser.execute name:'recipe'
|
parser.execute name:'recipe'
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.item.id.should.equal 0
|
recipe.item.id.should.equal 0
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
describe 'quantity', ->
|
describe 'quantity', ->
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
it 'assigns to the current recipe', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'quantity', argText:'42'
|
parser.execute name:'quantity', argText:'42'
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.quantity.should.equal 42
|
recipe.quantity.should.equal 42
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|
||||||
describe 'tools', ->
|
describe 'tools', ->
|
||||||
|
|
||||||
it 'assigns to the current recipe', ->
|
it 'assigns to the current recipe', ->
|
||||||
state.create {}, 'recipe'
|
data.create {}, 'recipe'
|
||||||
|
|
||||||
parser.execute name:'tools', args:['bravo']
|
parser.execute name:'tools', args:['bravo']
|
||||||
.then ->
|
recipe = data.getCurrent 'recipe'
|
||||||
recipe = state.getCurrent 'recipe'
|
|
||||||
recipe.tools.should.eql [name:'bravo', quantity:1]
|
recipe.tools.should.eql [name:'bravo', quantity:1]
|
||||||
state.errors.should.eql []
|
data.errors.should.eql []
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
#
|
|
||||||
# Crafting Guide - parser_state.test.coffee
|
|
||||||
#
|
|
||||||
# Copyright © 2014-2016 by Redwood Labs
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
|
|
||||||
ParserCommand = require './parser_command'
|
|
||||||
ParserState = require './parser_state'
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
command = state = null
|
|
||||||
|
|
||||||
########################################################################################################################
|
|
||||||
|
|
||||||
describe 'parser_state.coffee', ->
|
|
||||||
|
|
||||||
beforeEach ->
|
|
||||||
state = new ParserState
|
|
||||||
command = new ParserCommand name:'alpha', fileName:'file.cg', lineNumber:1
|
|
||||||
|
|
||||||
describe 'create', ->
|
|
||||||
|
|
||||||
it 'returns an object with the given id', ->
|
|
||||||
alpha = state.create command, 'alpha', 0
|
|
||||||
alpha.id.should.equal 0
|
|
||||||
alpha.command.location.should.equal 'file.cg:1'
|
|
||||||
|
|
||||||
it 'returns an object with a newly created id when none is given', ->
|
|
||||||
alpha = state.create command, 'alpha'
|
|
||||||
alpha.id.should.not.be.null
|
|
||||||
alpha.id.should.match /^alpha-[0-9]+$/
|
|
||||||
alpha.command.location.should.equal 'file.cg:1'
|
|
||||||
|
|
||||||
describe 'each', ->
|
|
||||||
|
|
||||||
it 'ignores the callback when there are no items', ->
|
|
||||||
items = []
|
|
||||||
state.each (item)-> items.push item
|
|
||||||
items.length.should.equal 0
|
|
||||||
|
|
||||||
it 'calls the callback once with a single item', ->
|
|
||||||
state.create command, 'alpha', 0
|
|
||||||
items = []
|
|
||||||
state.each (item)-> items.push item
|
|
||||||
items.length.should.equal 1
|
|
||||||
items[0].id.should.equal 0
|
|
||||||
|
|
||||||
it 'calls the callback for each item of a single type', ->
|
|
||||||
state.create command, 'alpha', 0
|
|
||||||
state.create command, 'alpha', 1
|
|
||||||
state.create command, 'alpha', 2
|
|
||||||
|
|
||||||
ids = []
|
|
||||||
state.each (item)-> ids.push item.id
|
|
||||||
ids.should.eql [0, 1, 2]
|
|
||||||
|
|
||||||
it 'calls the callback for each item across multiple types', ->
|
|
||||||
state.create command, 'alpha', 0
|
|
||||||
state.create command, 'alpha', 1
|
|
||||||
state.create command, 'bravo', 0
|
|
||||||
state.create command, 'bravo', 1
|
|
||||||
|
|
||||||
ids = []
|
|
||||||
state.each (item)-> ids.push "#{item.type}-#{item.id}"
|
|
||||||
ids.should.eql ['alpha-0', 'alpha-1', 'bravo-0', 'bravo-1']
|
|
||||||
|
|
||||||
describe 'eachOfType', ->
|
|
||||||
|
|
||||||
it 'ignores the callback if there are no items of that type', ->
|
|
||||||
state.create command, 'alpha', 0
|
|
||||||
state.create command, 'alpha', 1
|
|
||||||
|
|
||||||
ids = []
|
|
||||||
state.eachOfType 'bravo', (item)-> ids.push "#{item.type}-#{item.id}"
|
|
||||||
ids.length.should.equal 0
|
|
||||||
|
|
||||||
it 'calls the callback once for each item of the given type', ->
|
|
||||||
state.create command, 'alpha', 0
|
|
||||||
state.create command, 'alpha', 1
|
|
||||||
state.create command, 'bravo', 0
|
|
||||||
state.create command, 'bravo', 1
|
|
||||||
|
|
||||||
ids = []
|
|
||||||
state.eachOfType 'bravo', (item)-> ids.push "#{item.type}-#{item.id}"
|
|
||||||
ids.should.eql ['bravo-0', 'bravo-1']
|
|
||||||
|
|
||||||
describe 'get', ->
|
|
||||||
|
|
||||||
it 'returns a previously created item', ->
|
|
||||||
alpha1 = state.create command, 'alpha', 0
|
|
||||||
alpha2 = state.get 'alpha', 0
|
|
||||||
alpha1.should.equal alpha2
|
|
||||||
|
|
||||||
it 'returns null when no such item exists', ->
|
|
||||||
alpha = state.create command, 'alpha', 0
|
|
||||||
expect(state.get 'alpha', 1).to.be.null
|
|
||||||
expect(state.get 'bravo', 0).to.be.null
|
|
||||||
|
|
||||||
describe 'getCurrent', ->
|
|
||||||
|
|
||||||
it 'returns the new item each time one is created', ->
|
|
||||||
alpha1 = state.create command, 'alpha', 0
|
|
||||||
state.getCurrent('alpha').id.should.equal 0
|
|
||||||
|
|
||||||
alpha2 = state.create command, 'alpha', 1
|
|
||||||
state.getCurrent('alpha').id.should.equal 1
|
|
||||||
Reference in New Issue
Block a user