Skip to content

Commit

Permalink
Merge pull request #89 from grafana/feat/support-scenarios
Browse files Browse the repository at this point in the history
Feat/support scenarios
  • Loading branch information
w1kman authored Dec 6, 2021
2 parents d715509 + 55e92db commit b009254
Show file tree
Hide file tree
Showing 37 changed files with 1,291 additions and 205 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
test/*
typings/*
loadtest.js
1 change: 1 addition & 0 deletions li-har.spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ interface Log {
pages?: Array // List of exported pages
entries?: Array // List of exported requests
comment?: Check // A comment provided by the user or the application
exportAs?: String // Export parsed HAR as named function rather than "export default function main()..."
}
```

Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@
"test": "npm-run-all test-unit test-int test-e2e",
"test-int": "cross-env NODE_PATH=src:test ava test/int",
"test-unit": "cross-env NODE_PATH=src:test ava test/unit",
"test-e2e": "cross-env NODE_PATH=src:test ava test/e2e/run-tests.js",
"test-e2e": "cross-env NODE_PATH=src:test ava test/e2e/fixtures.test.js test/e2e/**/*.test.js",
"test:watch": "cross-env NODE_PATH=src:test ava --watch test/unit",
"test-hoc": "cross-env NODE_PATH=src:test ava",
"test-only": "cross-env NODE_PATH=src:test ava",
"prepare": "npm-run-all bundle"
Expand All @@ -93,9 +94,10 @@
]
},
"prettier": {
"trailingComma": "es5",
"semi": false,
"arrowParens": "avoid",
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 80
},
"husky": {
Expand Down
28 changes: 28 additions & 0 deletions src/combineExports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function combineExports(results) {
if (results.length <= 1) {
return
}

const functionNames = []
let defaultExported = false
let nameIndex = ''

for (const result of results) {
// Force `false` if default has already been exported
result.defaultExport = !defaultExported ? result.defaultExport : false
// Once true, remains true for the remaining iterations
defaultExported = defaultExported ? defaultExported : result.defaultExport
const { exportAs } = result
while (functionNames.includes(`${exportAs}${nameIndex}`)) {
nameIndex = nameIndex === '' ? 0 : nameIndex + 1
}

// Store exported name
functionNames.push(`${exportAs}${nameIndex}`)

// Use last stored name
result.exportAs = functionNames.slice(-1)[0]
}
}

module.exports = combineExports
18 changes: 18 additions & 0 deletions src/combineImports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function combineImports(results) {
const [main = {}] = results
const imports = { ...(main.imports || {}) }

if (results.length > 1) {
for (const result of results) {
Object.entries(result.imports || {}).forEach(([key, value]) => {
if (value === true || imports[key] === undefined) {
imports[key] = value
}
})
}
}

return imports
}

module.exports = combineImports
3 changes: 3 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ const DEFAULT_CLI_OPTIONS = {
output: 'loadtest.js',
}

const DEFAULT_FUNCTION_NAME = 'main'

module.exports = {
DEFAULT_OPTIONS,
DEFAULT_CLI_OPTIONS,
DEFAULT_FUNCTION_NAME,
}
39 changes: 34 additions & 5 deletions src/convert.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,46 @@ const render = require('./render')
const validate = require('./validate')
const normalize = require('./normalize')
const { DEFAULT_OPTIONS } = require('./constants')
const { InvalidArchiveError } = require('./error')
const combineImports = require('./combineImports')
const combineExports = require('./combineExports')

async function convert(archive, options = DEFAULT_OPTIONS) {
const source = normalize(archive, options)
/**
* Convert one or many HAR objects, into k6 script
* @param {HAR|Array<HAR>} _archives
* @param options
* @return {Promise<{main: *}>}
*/
async function convert(_archives, options = DEFAULT_OPTIONS) {
const isMultiConvert = Array.isArray(_archives)
const archives = !isMultiConvert ? [_archives] : _archives

validate(source)
const result = parse(source)
const result = archives.map((archive, index) => {
const source = normalize(archive, options)

try {
validate(source)
} catch (error) {
throw new InvalidArchiveError(
{ name: error.name },
isMultiConvert ? `Archive(${index}): ${error.message}` : error.message
)
}

return parse(source)
})

const imports = combineImports(result)

// combine exports to make sure we only have one default export and no
// colliding function names (result item (.exportAs and/or .defaultExport) is
// mutated) in place
combineExports(result)

// NOTE: => render(result) instead of { main: render(result) } ??
// Then /bin/har-to-k6.js need to change as well.
return {
main: render(result),
main: render(result, imports),
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/helpers/capitalize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Uppercase first character (capitalize)
* @param {string} subject
* @returns {string}
*/
function capitalize(subject) {
return typeof subject === 'string' && subject.length > 0
? `${subject.charAt(0).toUpperCase()}${subject.toLowerCase().slice(1)}`
: ''
}

module.exports = capitalize
121 changes: 121 additions & 0 deletions src/helpers/strToFunctionName.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const capitalize = require('./capitalize')
const { DEFAULT_FUNCTION_NAME } = require('../constants')

/** @see https://www.w3schools.com/js/js_reserved.asp */
const javascriptReservedWords = [
'abstract',
'arguments',
'await',
'boolean',
'break',
'byte',
'case',
'catch',
'char',
'class',
'const',
'continue',
'debugger',
'default',
'delete',
'do',
'double',
'else',
'enum',
'eval',
'export',
'extends',
'false',
'final',
'finally',
'float',
'for',
'function',
'goto',
'if',
'implements',
'import',
'in',
'instanceof',
'int',
'interface',
'let',
'long',
'native',
'new',
'null',
'package',
'private',
'protected',
'public',
'return',
'short',
'static',
'super',
'switch',
'synchronized',
'this',
'throw',
'throws',
'transient',
'true',
'try',
'typeof',
'var',
'void',
'volatile',
'while',
'with',
'yield',
]

const k6ReservedWords = [
// general
'options',
'__ITER',
'__VU',
'open',
// k6
'sleep',
'check',
'group',
// k6/http
'http',
// jslib
'jsonpath',
'MimeBuilder',
'FormData',
'URL',
'URLSearchParams',
]

const reservedWords = [...javascriptReservedWords, ...k6ReservedWords]

/**
* Convert string to valid function name
* @param {string} subject
* @param {string} fallback Name to use if subject becomes an empty string (IMPORTANT: no validation is done for this value)
* @returns {string}
*/
function strToFunctionName(subject = '', fallback = DEFAULT_FUNCTION_NAME) {
const words = String(subject)
.normalize('NFD')
// didnt dare to use unicode property escapes
// mainly because of older Edge versions
.replace(/[\u0300-\u036f]/g, '')
// convert camelCase into "words" so that proper names are not broken
.replace(/([A-Z])/g, ' $1')
.split(/\s/)
.map(word => word.replace(/\W/g, ''))
.filter(word => word)

// camelCase capitalization
const [firstWord = '', ...rest] = words
const result =
[firstWord.toLowerCase(), ...rest.map(word => capitalize(word))].join('') ||
fallback

return reservedWords.includes(result) ? `_${result}` : result
}

module.exports = strToFunctionName
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ module.exports = {
liHARToK6Script: require('./convert'),
validate: require('./validate'),
normalizeHAR: require('./normalize'),
strToFunctionName: require('./helpers/strToFunctionName'),
}
2 changes: 2 additions & 0 deletions src/make.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ function result() {
flow: [],
imports: imports(),
declares: new Set(),
exportAs: '',
defaultExport: true,
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/parse/exportAs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const strToFunctionName = require('../helpers/strToFunctionName')

function exportAs(value = '', result) {
const strValue = String(value)
if (strValue !== '') {
result.defaultExport = false
}

result.exportAs = strToFunctionName(strValue)
}

module.exports = exportAs
6 changes: 1 addition & 5 deletions src/parse/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@ const imports = require('./imports')
const root = require('./root')
const { result: makeResult } = require('../make')

/*
* Parse HAR archive
*
* Assumes valid archive.
*/
function parse(archive) {
const result = makeResult()
root(archive, result)
flow(result)
imports(archive, result)
declares(archive, result)

return result
}

Expand Down
3 changes: 3 additions & 0 deletions src/parse/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const creator = require('./creator')
const entries = require('./entries')
const pages = require('./pages')
const options = require('./options')
const exportAs = require('./exportAs')

function log(node, result) {
if (node.options) {
Expand All @@ -23,6 +24,8 @@ function log(node, result) {
if (node.entries) {
entries(node.entries, result)
}

exportAs(node.exportAs, result)
}

module.exports = log
4 changes: 2 additions & 2 deletions src/render/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const prettify = require('./prettify')
const root = require('./root')

function render(result) {
const raw = root(result)
function render(result, imports) {
const raw = root(result, imports)
return prettify(raw)
}

Expand Down
11 changes: 9 additions & 2 deletions src/render/logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,15 @@ function logic(result) {
variableSpace(result),
flow(result),
defaultSleep(result),
].filter((item) => item)
return `export default function main() ${block(content)}`
].filter(item => item)

const exportAs = result.exportAs ? result.exportAs : 'main'

// default unless defaultExport is explicitly set to false
const exportType =
result.defaultExport !== false ? 'export default' : 'export'

return `${exportType} function ${exportAs}() ${block(content)}`
}

module.exports = logic
5 changes: 4 additions & 1 deletion src/render/prettify.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ const babelParser = require('prettier/parser-babel')

function prettify(raw) {
return prettier.format(raw, {
semi: true,
semi: false,
arrowParens: 'avoid',
parser: 'babel',
plugins: [babelParser],
singleQuote: true,
trailingComma: 'es5',
printWidth: 100,
})
}

Expand Down
Loading

0 comments on commit b009254

Please sign in to comment.