From 2b148b772026ab1575a0eada70bc860734dd9c23 Mon Sep 17 00:00:00 2001 From: Ben Ogle Date: Mon, 20 Oct 2014 16:58:57 -0700 Subject: [PATCH] Accept escaped dots in config settings keys Fixes #3898 --- spec/config-spec.coffee | 6 +++++- src/config.coffee | 25 ++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/spec/config-spec.coffee b/spec/config-spec.coffee index 84561a93d..cdd071091 100644 --- a/spec/config-spec.coffee +++ b/spec/config-spec.coffee @@ -122,6 +122,11 @@ describe "Config", -> atom.config.set('.source.coffee', 'foo.bar.baz', 55) expect(atom.config.isDefault('.source.coffee', 'foo.bar.baz')).toBe false + describe ".setDefaults(keyPath)", -> + it "sets a default when the setting's key contains an escaped dot", -> + atom.config.setDefaults("foo", 'a\\.b': 1, b: 2) + expect(atom.config.get("foo")).toEqual 'a\\.b': 1, b: 2 + describe ".toggle(keyPath)", -> it "negates the boolean value of the current key path value", -> atom.config.set('foo.a', 1) @@ -213,7 +218,6 @@ describe "Config", -> baz: 42 omg: 'omg' - describe ".pushAtKeyPath(keyPath, value)", -> it "pushes the given value to the array at the key path and updates observers", -> atom.config.set("foo.bar.baz", ["a"]) diff --git a/src/config.coffee b/src/config.coffee index b5048ddbd..2fd30d924 100644 --- a/src/config.coffee +++ b/src/config.coffee @@ -590,7 +590,7 @@ class Config # Returns an {Object} eg. `{type: 'integer', default: 23, minimum: 1}`. # Returns `null` when the keyPath has no schema specified. getSchema: (keyPath) -> - keys = keyPath.split('.') + keys = splitKeyPath(keyPath) schema = @schema for key in keys break unless schema? @@ -670,7 +670,7 @@ class Config rootSchema = @schema if keyPath - for key in keyPath.split('.') + for key in splitKeyPath(keyPath) rootSchema.type = 'object' rootSchema.properties ?= {} properties = rootSchema.properties @@ -755,7 +755,7 @@ class Config unsetUnspecifiedValues = (keyPath, value) => if isPlainObject(value) - keys = if keyPath? then keyPath.split('.') else [] + keys = splitKeyPath(keyPath) for key, childValue of value continue unless value.hasOwnProperty(key) unsetUnspecifiedValues(keys.concat([key]).join('.'), childValue) @@ -768,7 +768,7 @@ class Config setRecursive: (keyPath, value) -> if isPlainObject(value) - keys = if keyPath? then keyPath.split('.') else [] + keys = splitKeyPath(keyPath) for key, childValue of value continue unless value.hasOwnProperty(key) @setRecursive(keys.concat([key]).join('.'), childValue) @@ -811,8 +811,8 @@ class Config isSubKeyPath: (keyPath, subKeyPath) -> return false unless keyPath? and subKeyPath? - pathSubTokens = subKeyPath.split('.') - pathTokens = keyPath.split('.').slice(0, pathSubTokens.length) + pathSubTokens = splitKeyPath(subKeyPath) + pathTokens = splitKeyPath(keyPath).slice(0, pathSubTokens.length) _.isEqual(pathTokens, pathSubTokens) setRawDefault: (keyPath, value) -> @@ -823,7 +823,7 @@ class Config setDefaults: (keyPath, defaults) -> if defaults? and isPlainObject(defaults) - keys = if keyPath? then keyPath.split('.') else [] + keys = splitKeyPath(keyPath) for key, childValue of defaults continue unless defaults.hasOwnProperty(key) @setDefaults(keys.concat([key]).join('.'), childValue) @@ -1044,3 +1044,14 @@ Config.addSchemaEnforcers isPlainObject = (value) -> _.isObject(value) and not _.isArray(value) and not _.isFunction(value) and not _.isString(value) + +splitKeyPath = (keyPath) -> + return [] unless keyPath? + startIndex = 0 + keyPathArray = [] + for char, i in keyPath + if char is '.' and (i is 0 or keyPath[i-1] != '\\') + keyPathArray.push keyPath.substring(startIndex, i) + startIndex = i + 1 + keyPathArray.push keyPath.substr(startIndex, keyPath.length) + keyPathArray