diff --git a/packages/heroku-cli-plugin-config/.gitignore b/packages/heroku-cli-plugin-config/.gitignore index fee49fd401..7ea55ed0e5 100644 --- a/packages/heroku-cli-plugin-config/.gitignore +++ b/packages/heroku-cli-plugin-config/.gitignore @@ -1,3 +1,4 @@ +/.nyc_output *-debug.log *-error.log .oclif.manifest.json diff --git a/packages/heroku-cli-plugin-config/package.json b/packages/heroku-cli-plugin-config/package.json index 90f4ace13b..d6d7575ae5 100644 --- a/packages/heroku-cli-plugin-config/package.json +++ b/packages/heroku-cli-plugin-config/package.json @@ -18,18 +18,18 @@ "@oclif/plugin-help": "^1.2.10", "@oclif/test": "^1.0.6", "@oclif/tslint": "1", - "@types/chai": "4", + "@types/chai": "^4.1.3", "@types/lodash": "^4.14.108", "@types/mocha": "5", "@types/node": "^10.0.3", "@types/supports-color": "^5.3.0", - "chai": "4", + "chai": "^4.1.2", "globby": "8", "mocha": "5", "nyc": "11", "ts-node": "6.0.2", "tslib": "1", - "tslint": "5", + "tslint": "5.10.0", "typescript": "2.8" }, "engines": { diff --git a/packages/heroku-cli-plugin-config/src/commands/config/edit.ts b/packages/heroku-cli-plugin-config/src/commands/config/edit.ts index a4da8d61a5..df432e77fb 100644 --- a/packages/heroku-cli-plugin-config/src/commands/config/edit.ts +++ b/packages/heroku-cli-plugin-config/src/commands/config/edit.ts @@ -3,7 +3,8 @@ import {Command, flags} from '@heroku-cli/command' import {cli} from 'cli-ux' import * as _ from 'lodash' -const shell = require('shell-quote') +import {parse, quote} from '../../quote' + const edit = require('edit-string') interface Config { @@ -35,18 +36,6 @@ function stringToConfig(s: string): Config { }, {}) } -function quote(a: string): string { - a = a.replace(/\n/g, '\\n') - if (a.match(/[:@]/)) return shell.quote([`'${a}`]).replace(/^"'/, '"') - return shell.quote([a]) -} - -function parse(a: string): string { - let parsed = shell.parse(a) - if (parsed.length > 1) throw new Error(`Invalid token: ${a}`) - return parsed[0].replace(/\\\\n/g, '\n') -} - function allKeys(a: Config, b: Config): string[] { return _.uniq([...Object.keys(a), ...Object.keys(b)].sort()) } diff --git a/packages/heroku-cli-plugin-config/src/quote.ts b/packages/heroku-cli-plugin-config/src/quote.ts new file mode 100644 index 0000000000..c57877a231 --- /dev/null +++ b/packages/heroku-cli-plugin-config/src/quote.ts @@ -0,0 +1,26 @@ +const shell = require('shell-quote') + +// slightly modifed form of shell-quote to default to using single-quotes over backslashes +export function quote(s: string): string { + if (/["\s#!$&'()*,:;<=>?@\[\\\]^`{|}]/.test(s)) { + if (/['\n]/.test(s)) return '"' + + s + .replace(/(["\\$`!])/g, '\\$1') + .replace(/\n/g, '\\n') + + '"' + return "'" + s.replace(/(['\\])/g, '\\$1') + "'" + } + return s +} + +export function parse(a: string): string { + if (a.startsWith('"')) { + a = a.replace(/\\n/g, '\n') + } else if (a.startsWith("'")) { + a = a.replace(/\\\\/g, '\\') + } + let parsed = shell.parse(a) + if (parsed.length > 1) throw new Error(`Invalid token: ${a}`) + return parsed[0] + // return parsed[0].replace(/\\\\n/g, '\n') +} diff --git a/packages/heroku-cli-plugin-config/test/commands/hello.test.ts b/packages/heroku-cli-plugin-config/test/commands/hello.test.ts deleted file mode 100644 index 8f243040b4..0000000000 --- a/packages/heroku-cli-plugin-config/test/commands/hello.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import {expect, test} from '@oclif/test' - -describe('hello', () => { - test - .skip() - .stdout() - .command(['hello']) - .it('runs hello', ctx => { - expect(ctx.stdout).to.contain('hello world') - }) -}) diff --git a/packages/heroku-cli-plugin-config/test/quote.test.ts b/packages/heroku-cli-plugin-config/test/quote.test.ts new file mode 100644 index 0000000000..8558468c70 --- /dev/null +++ b/packages/heroku-cli-plugin-config/test/quote.test.ts @@ -0,0 +1,29 @@ +import {expect} from 'chai' + +import {parse, quote} from '../src/quote' + +describe('quote', () => { + [ + ['abc', 'abc'], + ['ab$c', "'ab$c'"], + ['a\'bc', '"a\'bc"'], + ['a\nb\nc', '"a\\nb\\nc"'], + ['foo\\nb:ar\\bz', "'foo\\\\nb:ar\\\\bz'"], + ].map(([a, b]) => { + it(`${a}===${b}`, () => { + expect(quote(a)).to.eq(b) + }) + }); + + [ + 'abc', + 'ab$c', + 'a\'bc', + 'a\nb\nc', + 'foo\\nb:ar\\bz', + ].map(s => { + it(`parses "${s}"`, () => { + expect(parse(quote(s))).to.eq(s) + }) + }) +}) diff --git a/packages/heroku-cli-plugin-config/yarn.lock b/packages/heroku-cli-plugin-config/yarn.lock index d958599c01..3c6e8c2212 100644 --- a/packages/heroku-cli-plugin-config/yarn.lock +++ b/packages/heroku-cli-plugin-config/yarn.lock @@ -136,7 +136,7 @@ dependencies: tslint-xo "^0.7.0" -"@types/chai@4": +"@types/chai@^4.1.3": version "4.1.3" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.3.tgz#b8a74352977a23b604c01aa784f5b793443fb7dc" @@ -458,7 +458,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chai@4: +chai@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chai/-/chai-4.1.2.tgz#0f64584ba642f0f2ace2806279f4f06ca23ad73c" dependencies: @@ -2458,9 +2458,9 @@ tslint-xo@^0.7.0: tslint-eslint-rules "^5.1.0" tslint-microsoft-contrib "^5.0.2" -tslint@5: - version "5.9.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.9.1.tgz#1255f87a3ff57eb0b0e1f0e610a8b4748046c9ae" +tslint@5.10.0: + version "5.10.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.10.0.tgz#11e26bccb88afa02dd0d9956cae3d4540b5f54c3" dependencies: babel-code-frame "^6.22.0" builtin-modules "^1.1.1"