mirror of
https://github.com/atom/atom.git
synced 2026-01-21 04:48:12 -05:00
Merge pull request #3907 from atom/bo-scoped-schema
Add support for scoped defaults in config schemas
This commit is contained in:
@@ -60,7 +60,7 @@
|
||||
"temp": "0.7.0",
|
||||
"text-buffer": "^3.2.9",
|
||||
"theorist": "^1.0.2",
|
||||
"underscore-plus": "^1.5.1",
|
||||
"underscore-plus": "^1.6.0",
|
||||
"vm-compatibility-layer": "0.1.0"
|
||||
},
|
||||
"packageDependencies": {
|
||||
|
||||
@@ -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"])
|
||||
@@ -1032,6 +1036,21 @@ describe "Config", ->
|
||||
expect(atom.config.set('foo.bar.arr', ['two', 'three'])).toBe true
|
||||
expect(atom.config.get('foo.bar.arr')).toEqual ['two', 'three']
|
||||
|
||||
describe "when scoped settings are used", ->
|
||||
beforeEach ->
|
||||
schema =
|
||||
type: 'string'
|
||||
default: 'ok'
|
||||
scopes:
|
||||
'.source.js':
|
||||
default: 'omg'
|
||||
atom.config.setSchema('foo.bar.str', schema)
|
||||
|
||||
it 'it respects the scoped defaults', ->
|
||||
expect(atom.config.get('foo.bar.str')).toBe 'ok'
|
||||
expect(atom.config.get(['.source.js'], 'foo.bar.str')).toBe 'omg'
|
||||
expect(atom.config.get(['.source.coffee'], 'foo.bar.str')).toBe 'ok'
|
||||
|
||||
describe "scoped settings", ->
|
||||
describe ".get(scopeDescriptor, keyPath)", ->
|
||||
it "returns the property with the most specific scope selector", ->
|
||||
|
||||
@@ -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
|
||||
@@ -679,6 +679,7 @@ class Config
|
||||
|
||||
_.extend rootSchema, schema
|
||||
@setDefaults(keyPath, @extractDefaultsFromSchema(schema))
|
||||
@setScopedDefaultsFromSchema(keyPath, schema)
|
||||
|
||||
load: ->
|
||||
@initializeConfigDirectory()
|
||||
@@ -754,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)
|
||||
@@ -767,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)
|
||||
@@ -810,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) ->
|
||||
@@ -822,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)
|
||||
@@ -833,6 +834,32 @@ class Config
|
||||
catch e
|
||||
console.warn("'#{keyPath}' could not set the default. Attempted default: #{JSON.stringify(defaults)}; Schema: #{JSON.stringify(@getSchema(keyPath))}")
|
||||
|
||||
# `schema` will look something like this
|
||||
#
|
||||
# ```coffee
|
||||
# type: 'string'
|
||||
# default: 'ok'
|
||||
# scopes:
|
||||
# '.source.js':
|
||||
# default: 'omg'
|
||||
# ```
|
||||
setScopedDefaultsFromSchema: (keyPath, schema) ->
|
||||
if schema.scopes? and isPlainObject(schema.scopes)
|
||||
scopedDefaults = {}
|
||||
for scope, scopeSchema of schema.scopes
|
||||
continue unless scopeSchema.hasOwnProperty('default')
|
||||
scopedDefaults[scope] = {}
|
||||
_.setValueForKeyPath(scopedDefaults[scope], keyPath, scopeSchema.default)
|
||||
@scopedSettingsStore.addProperties('schema-default', scopedDefaults)
|
||||
|
||||
if schema.type is 'object' and schema.properties? and isPlainObject(schema.properties)
|
||||
keys = splitKeyPath(keyPath)
|
||||
for key, childValue of schema.properties
|
||||
continue unless schema.properties.hasOwnProperty(key)
|
||||
@setScopedDefaultsFromSchema(keys.concat([key]).join('.'), childValue)
|
||||
|
||||
return
|
||||
|
||||
extractDefaultsFromSchema: (schema) ->
|
||||
if schema.default?
|
||||
schema.default
|
||||
@@ -1017,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
|
||||
|
||||
Reference in New Issue
Block a user