Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@wmfs/tymly-statelint

Package Overview
Dependencies
Maintainers
1
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wmfs/tymly-statelint - npm Package Compare versions

Comparing version 1.8.0 to 1.9.0

test/fixtures/run-function-with-parameters/parameters-schema.j2119

13

CHANGELOG.md

@@ -0,1 +1,14 @@

# [1.9.0](https://github.com/wmfs/tymly-statelint/compare/v1.8.0...v1.9.0) (2019-03-21)
### ✨ Features
* Complete Parameters validation. ([85d3f8b](https://github.com/wmfs/tymly-statelint/commit/85d3f8b))
* Start on Parameters validation ([62b63c3](https://github.com/wmfs/tymly-statelint/commit/62b63c3))
### 🐛 Bug Fixes
* Silence one of the warnings. Too many atm, so not helpful. ([d17fc39](https://github.com/wmfs/tymly-statelint/commit/d17fc39))
# [1.8.0](https://github.com/wmfs/tymly-statelint/compare/v1.7.0...v1.8.0) (2019-03-20)

@@ -2,0 +15,0 @@

169

lib/task_node.js

@@ -5,2 +5,5 @@ const path = require('path')

const jsonSchemaValidator = require('./json_schema_loader')
const kebabCase = require('lodash.kebabcase')
const cloneDeep = require('lodash.clonedeep')
const isPath = require('@wmfs/j2119/lib/j2119/json_path_checker').isPath

@@ -18,7 +21,11 @@ const moduleRegex = /^(module|function):(.+)$/

this.functions = functions
this.validators = { }
this.validators = {
'Resource': { },
'ResourceConfig': { },
'Parameters': { }
}
this.logger = logger
if (!this.resources) {
this.logger.warn('State Resources not available. Will not validate Resource or ResourceConfig')
this.logger.warn('State Resources not available. Will not validate Resource, ResourceConfig or Parameters')
}

@@ -58,3 +65,7 @@ } // constructor

const [ , resourceType, resourceName ] = resource
if (resourceType === 'module') { this.checkResource(name, state, resourceName) } else if (resourceType === 'function') { this.checkFunction(name, resourceName) }
if (resourceType === 'module') {
this.checkResource(name, state, resourceName)
} else if (resourceType === 'function') {
this.checkFunction(name, resourceName)
}
} // checkTask

@@ -69,21 +80,107 @@

this.checkResourceConfig(name, resourceName, state.ResourceConfig)
const resourceConfig = state.ResourceConfig
const [parameters, fixUps] = processReplacements(state.Parameters)
const rcOk = this.checkResourceConfig(name, resourceName, resourceConfig)
const pOk = this.checkParameters(name, resourceName, parameters, fixUps)
if (rcOk && pOk) return
const validator = this.findValidator(resourceName, 'Resource')
if (validator && !resourceConfig && !parameters) {
/* silence this for the moment
this.problems.push(
`State Machine.States.${name} has no ResourceConfig or Parameters object, but validation schema found.`
)
*/
return
}
const usedValidator = this.recheckResourceConfig(name, resourceConfig, rcOk, validator)
this.recheckParameters(name, state.Parameters, pOk, usedValidator ? null : validator, fixUps)
} // checkResource
recheckResourceConfig (name, resourceConfig, alreadyOk, validator) {
return this.recheckSubObject(name, resourceConfig, 'ResourceConfig', alreadyOk, validator)
} // recheckResourceConfig
recheckParameters (name, parameters, alreadyOk, validator, fixUps) {
return this.recheckSubObject(name, parameters, 'Parameters', alreadyOk, validator, fixUps)
} // recheckParameters
recheckSubObject (name, subObject, objectType, alreadyOk, validator, fixUps) {
if (alreadyOk || !subObject) {
return false
}
if (validator) {
return this.validateSubObject(name, subObject, objectType, validator, fixUps)
} else {
this.problems.push(
`State Machine.States.${name}.${objectType} exists, but no validator found`
)
}
} // recheckSubObject
checkResourceConfig (name, resourceName, resourceConfig) {
const validator = this.findValidator(resourceName)
return this.checkSubObject(name, resourceName, resourceConfig, 'ResourceConfig')
}
const problems = validator.validate(resourceConfig || {})
checkParameters (name, resourceName, parameters, fixUps) {
for (const [field, path] of fixUps) {
if (!isPath(path)) {
this.problems.push(
`State Machine.States.${name} Field "${field}" must be a Path`
)
}
}
return this.checkSubObject(name, resourceName, parameters, 'Parameters', fixUps)
} // checkParameters
checkSubObject (name, resourceName, subObject, objectType, fixUps) {
const validator = this.findValidator(resourceName, objectType)
if (!validator) return
return this.validateSubObject(name, subObject, objectType, validator, fixUps)
} // checkSubObject
validateSubObject (name, subObject, objectType, validator, fixUps = []) {
const problems = validator.validate(subObject || {})
.filter(p => this.applyFixUps(p, fixUps))
problems.forEach(p =>
this.problems.push(`State Machine.States.${name}.ResourceConfig ${p}`)
this.problems.push(`State Machine.States.${name}.${objectType} ${p}`)
)
} // checkResourceConfig
return true
} // validateSubObject
findValidator (resourceName) {
if (this.validators[resourceName]) {
return this.validators[resourceName]
applyFixUps (p, fixUps = []) {
for (const [replacementName] of fixUps) {
const notAllowed = `Field "${replacementName}" not allowed`
if (p.indexOf(notAllowed) !== -1) return false
const fieldName = replacementName.substring(0, replacementName.length - 2)
const doesNotHave = `does not have required field "${fieldName}"`
if (p.indexOf(doesNotHave) !== -1) return false
} // for ...
return true
} // applyFixUps
findValidator (resourceName, objectType) {
const validators = this.validators[objectType]
if (validators[resourceName]) {
return validators[resourceName]
}
const validator = loadValidator(resourceName, this.resources[resourceName].rootDirPath, this.logger)
this.validators[resourceName] = validator
const validator = loadValidator(
resourceName,
this.resources[resourceName].rootDirPath,
objectType,
this.logger
)
validators[resourceName] = validator
return validator

@@ -101,9 +198,10 @@ } // findValidator

const nullValidator = {
validate: () => []
} // nullValidator
/// ///////////////////////////////////////////////
function loadValidator (resourceName, rootDir, objectType, logger) {
const schemaName = (objectType !== 'Resource')
? `${kebabCase(objectType)}-schema`
: 'schema'
function loadValidator (resourceName, rootDir, logger) {
for (const [schemaType, validatorLoader] of Object.entries(schemaTypes)) {
const schemaFile = path.resolve(rootDir, `schema.${schemaType}`)
const schemaFile = path.resolve(rootDir, `${schemaName}.${schemaType}`)
if (fs.existsSync(schemaFile)) {

@@ -113,4 +211,4 @@ try {

} catch (err) {
logger.error(`Couldn't load ResourceConfig schema for ${resourceName}:\n ${err.message}`)
return nullValidator
logger.error(`Couldn't load ${objectType} schema for ${resourceName}:\n ${err.message}`)
return null
}

@@ -120,4 +218,3 @@ } // if ...

logger.warn(`No ResourceConfig schema available for ${resourceName}`)
return nullValidator
return null
} // loadValidator

@@ -129,2 +226,30 @@

/// ///////////////////////////////////////////////////
function processReplacements (parameters) {
if (!parameters) {
return [ null, [] ]
}
const params = cloneDeep(parameters)
const replacements = findSelectors(params)
return [ params, replacements ]
}
function findSelectors (params, path = [], selectors = []) {
for (const [key, value] of Object.entries(params)) {
if (isSelector(key)) {
selectors.push([ key, value ])
} else if (typeof value === 'object') {
findSelectors(value, [...path, key], selectors)
}
} // findSelectors
return selectors
} // findSelectors
function isSelector (path) {
return path.endsWith('.$')
} // isSelector
module.exports = (stateResources, functions, logger) => new CheckTaskNodes(stateResources, functions, logger)

6

package.json
{
"name": "@wmfs/tymly-statelint",
"version": "1.8.0",
"version": "1.9.0",
"description": "Validator for Amazon States Language with Tymly Extensions JSON.",

@@ -28,3 +28,5 @@ "author": "West Midlands Fire Service",

"@wmfs/statelint": "1.7.1",
"ajv": "6.5.5"
"ajv": "6.5.5",
"lodash.clonedeep": "4.5.0",
"lodash.kebabcase": "4.1.1"
},

@@ -31,0 +33,0 @@ "devDependencies": {

@@ -16,2 +16,8 @@ /* eslint-env mocha */

},
RCFunction: {
rootDirPath: path.resolve(__dirname, './fixtures/run-function-with-resource-config/')
},
ParamFunction: {
rootDirPath: path.resolve(__dirname, './fixtures/run-function-with-parameters/')
},
CallFunction: {

@@ -117,3 +123,3 @@ rootDirPath: path.resolve(__dirname, './fixtures/call-function/')

describe('Task ResourceConfig validation with J2119 validator', () => {
describe('Task ResourceConfig validation with resource-config-schema.j2119', () => {
const machine = {

@@ -124,3 +130,3 @@ StartAt: 'A',

Type: 'Task',
Resource: 'module:RunFunction',
Resource: 'module:RCFunction',
End: true

@@ -176,2 +182,77 @@ }

describe('Task Parameters validation with parameters-schema.j2119', () => {
const machine = {
StartAt: 'A',
States: {
A: {
Type: 'Task',
Resource: 'module:ParamFunction',
End: true
}
}
}
verify(
'Parameters is missing',
machine,
1
)
machine.States.A['Parameters'] = {
'function': 'getFruitName',
'parameter': 'chirimoya'
}
verify(
'Parameters has incorrect fields',
machine,
3
)
machine.States.A['Parameters'] = {
functionName: 100
}
verify(
'Parameters is has incorrect type',
machine,
1
)
machine.States.A['Parameters'] = {
functionName: 'isBanana',
debug: true
}
verify(
'Parameters is has additional field',
machine,
1
)
machine.States.A['Parameters'] = {
functionName: 'isBanana'
}
verify(
'Parameters validates',
machine,
0
)
machine.States.A['Parameters'] = {
'functionName.$': '$.isBanana'
}
verify(
'Parameters validates when extracting values',
machine,
0
)
machine.States.A['Parameters'] = {
'functionName.$': 'Wango'
}
verify(
'Parameters extract value must be a Path ',
machine,
1
)
})
describe('Task ResourceConfig validation with JSON schema validator', () => {

@@ -192,3 +273,3 @@ const machine = {

machine,
1
0
)

@@ -234,2 +315,143 @@

})
describe('Task ResourceConfig & Parameter validation with schema.j2119', () => {
const machine = {
StartAt: 'A',
States: {
A: {
Type: 'Task',
Resource: 'module:RunFunction',
End: true
}
}
}
verify(
'Both ResourceConfig and Parameters are missing',
machine,
0
)
describe('ResourceConfig present so will be validated', () => {
machine.States.A['ResourceConfig'] = {
'function': 'getFruitName',
'parameter': 'chirimoya'
}
verify(
'ResourceConfig has incorrect fields',
machine,
3
)
machine.States.A['ResourceConfig'] = {
functionName: 100
}
verify(
'ResourceConfig is has incorrect type',
machine,
1
)
machine.States.A['ResourceConfig'] = {
functionName: 'isBanana',
debug: true
}
verify(
'ResourceConfig is has additional field',
machine,
1
)
machine.States.A['ResourceConfig'] = {
functionName: 'isBanana'
}
verify(
'ResourceConfig validates',
machine,
0
)
delete machine.States.A['ResourceConfig']
})
describe('No ResourceConfig, Parameters present so validate those', () => {
machine.States.A['Parameters'] = {
'function': 'getFruitName',
'parameter': 'chirimoya'
}
verify(
'Parameters has incorrect fields',
machine,
3
)
machine.States.A['Parameters'] = {
functionName: 100
}
verify(
'Parameters is has incorrect type',
machine,
1
)
machine.States.A['Parameters'] = {
functionName: 'isBanana',
debug: true
}
verify(
'Parameters is has additional field',
machine,
1
)
machine.States.A['Parameters'] = {
functionName: 'isBanana'
}
verify(
'Parameters validates',
machine,
0
)
})
describe('Both ResourceConfig and Parameters present. Validate ResourceConfig error on Parameters', () => {
machine.States.A['ResourceConfig'] = {
'function': 'getFruitName',
'parameter': 'chirimoya'
}
verify(
'ResourceConfig has incorrect fields',
machine,
4
)
machine.States.A['ResourceConfig'] = {
functionName: 100
}
verify(
'ResourceConfig is has incorrect type',
machine,
2
)
machine.States.A['ResourceConfig'] = {
functionName: 'isBanana',
debug: true
}
verify(
'ResourceConfig is has additional field',
machine,
2
)
machine.States.A['ResourceConfig'] = {
functionName: 'isBanana'
}
verify(
'ResourceConfig validates',
machine,
1
)
})
})
})

@@ -236,0 +458,0 @@

@@ -6,3 +6,2 @@ /* eslint-env mocha */

const expect = chai.expect
const fs = require('fs')
const path = require('path')

@@ -21,3 +20,9 @@

for (const file of fs.readdirSync(fixturesDir).filter(f => f.endsWith('.json'))) {
const fixtures = [
['timestamp.json', 0],
['hmo.json', 2],
['building-dna.json', 11]
]
for (const [file, errors] of fixtures) {
it(file, () => {

@@ -30,3 +35,3 @@ const linter = tymlyStateLint(stateResources, nullLogger)

expect(problems).to.eql([])
expect(problems.length).to.eql(stateResources ? errors : 0)
})

@@ -49,3 +54,3 @@ }

describe('TymlyStateMachineLint', () => {
tests()
tests(null)
tests(stateResources)

@@ -64,13 +69,5 @@ describe('logger', () => {

expect(logger.logs).to.eql(['State Resources not available. Will not validate Resource or ResourceConfig'])
expect(logger.logs).to.eql(['State Resources not available. Will not validate Resource, ResourceConfig or Parameters'])
})
it('warning when no state resource schema available', () => {
const logger = new TestLogger()
const linter = tymlyStateLint(stateResources, null, logger)
linter.validate(require(path.join(fixturesDir, 'timestamp.json')))
expect(logger.logs).to.eql(['No ResourceConfig schema available for timestamp'])
})
})
})

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc