Skip to content
This repository has been archived by the owner on Jul 19, 2021. It is now read-only.

Commit

Permalink
Refactor slate-config to simplified schema
Browse files Browse the repository at this point in the history
- Refactor @shopify/slate-config to use new config structure
- Replace all config schemas with new structure
- Replace all usage of config items with new .get() format
- Fix any exisiting tests for config items
  • Loading branch information
t-kelly committed Sep 6, 2018
1 parent fb7b1ac commit fb117e0
Show file tree
Hide file tree
Showing 51 changed files with 735 additions and 913 deletions.
10 changes: 0 additions & 10 deletions packages/slate-config/__tests__/fixtures/otherSchema.js

This file was deleted.

8 changes: 2 additions & 6 deletions packages/slate-config/__tests__/fixtures/slate.config.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
module.exports = {
testSchema: {
'test-item': 'override-value',
},
otherSchema: {
'other-item': 'other-value',
},
'some.key': 'override-value',
'other.item': 'other-value',
};
10 changes: 0 additions & 10 deletions packages/slate-config/__tests__/fixtures/testSchema.js

This file was deleted.

139 changes: 96 additions & 43 deletions packages/slate-config/__tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,98 @@
const slateConfig = require('../index');
const testSchema = require('./fixtures/testSchema');
const otherSchema = require('./fixtures/otherSchema');

describe('.generate()', () => {
describe('can generate a config object', () => {
test('with default values', () => {
const config = slateConfig.generate(testSchema);

expect(config).toHaveProperty(
testSchema.items[0].id,
testSchema.items[0].default,
);
});

test('with slaterc overrides', () => {
const mockSlateRc = require('./fixtures/slate.config.js');
const config = slateConfig.generate(testSchema, mockSlateRc);

expect(config).toHaveProperty(testSchema.items[0].id, 'override-value');
});

test('with namespaced settings', () => {
const mockSlateRc = require('./fixtures/slate.config.js');
const config1 = slateConfig.generate(testSchema, mockSlateRc);
const config2 = slateConfig.generate(otherSchema, mockSlateRc);

expect(config1).toHaveProperty(
testSchema.items[0].id,
mockSlateRc[testSchema.id][testSchema.items[0].id],
);
expect(config2).toHaveProperty(
otherSchema.items[0].id,
mockSlateRc[otherSchema.id][otherSchema.items[0].id],
);
});

test('with the schema used to generate the config', () => {
const config = slateConfig.generate(testSchema);

expect(config).toHaveProperty('__schema');
expect(config.__schema).toEqual(testSchema);
});
const path = require('path');

const originalCwd = process.cwd();
const schema = {
'some.key': 'someValue',
'some.other.key': 'someOtherValue',
'some.function': jest.fn((config) => config.get('some.other.key')),
};

describe('SlateConfig()', () => {
beforeEach(() => {
process.chdir(originalCwd);
jest.resetModules();
global.slateUserConfig = null;
});

test('requires a first argument which is assigned to this.schema', () => {
const SlateConfig = require('../index');
const config = new SlateConfig(schema);

expect(config.schema).toMatchObject(schema);
expect(() => new SlateConfig()).toThrowError();
});

test('has an optional second argument which is assigned to this.userConfig', () => {
const SlateConfig = require('../index');
const userConfig = {
'some.key': 'someNewValue',
};
const config = new SlateConfig(schema, userConfig);

expect(config.userConfig).toBe(userConfig);
});

test('if a second argument is undefined, assigns the contents of a the slate.config.js file in the cwd to this.userConfig', () => {
process.chdir(path.resolve(__dirname, './fixtures'));

const SlateConfig = require('../index');
const userConfig = require('./fixtures/slate.config');
const config = new SlateConfig(schema);

expect(config.userConfig).toMatchObject(userConfig);
});

test('copies the values of this.userConfig into this.schema, replacing any exisiting values', () => {
const SlateConfig = require('../index');
const userConfig = {
'some.key': 'someNewValue',
};
const config = new SlateConfig(schema, userConfig);

expect(config.schema).toMatchObject(config.userConfig);
});
});

describe('SlateConfig.get()', () => {
test('fetches the value of the provided key', () => {
const SlateConfig = require('../index');
const config = new SlateConfig(schema);

expect(config.get('some.other.key')).toBe(schema['some.other.key']);
});

test('if the value is a function, the function is executed with the config instance as the only argument', () => {
const SlateConfig = require('../index');
const config = new SlateConfig(schema);
const value = config.get('some.function');

expect(schema['some.function']).toBeCalledWith(config);
expect(value).toBe(schema['some.other.key']);
});

test('if the value is a function, it is replaced with the returned value of that function after .get() has been called', () => {
const SlateConfig = require('../index');
const config = new SlateConfig(schema);
const value = config.get('some.function');

expect(config.schema['some.function']).toBe(value);
});
});

describe('SlateConfig.set()', () => {
test('sets the value of a config for a given key', () => {
const SlateConfig = require('../index');
const config = new SlateConfig(schema);

config.set('some.new.key', 'someNewValue');

expect(config.schema['some.new.key']).toBe('someNewValue');
});

test('throws an error if key has already been set, unless override boolean has been explicitely set', () => {
const SlateConfig = require('../index');
const config = new SlateConfig(schema);

expect(() => config.set('some.key', 'someOtherValue')).toThrowError();
});
});
32 changes: 0 additions & 32 deletions packages/slate-config/__tests__/validate.test.js

This file was deleted.

84 changes: 84 additions & 0 deletions packages/slate-config/common/paths.schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const path = require('path');

module.exports = {
// Returns the root directory of the theme
'paths.theme': process.cwd(),

// Theme node_modules directory
'paths.theme.nodeModules': (config) =>
path.join(config.get('paths.theme'), 'node_modules'),

// Theme package.json file
'paths.theme.packageJson': (config) =>
path.join(config.get('paths.theme'), 'package.json'),

// Source directory of theme
'paths.theme.src': (config) => path.join(config.get('paths.theme'), 'src'),

// Source of theme configuration files
'paths.theme.src.config': (config) =>
path.join(config.get('paths.theme.src'), 'config'),

// Source font directory for theme
'paths.theme.src.fonts': (config) =>
path.join(config.get('paths.theme.src'), 'assets', 'fonts'),

// Source of images directory
'paths.theme.src.images': (config) =>
path.join(config.get('paths.theme.src'), 'assets', 'images'),

// Source of theme liquid layout files
'paths.theme.src.layouts': (config) =>
path.join(config.get('paths.theme.src'), 'layout'),

// Source of translation locales
'paths.theme.src.locales': (config) =>
path.join(config.get('paths.theme.src'), 'locales'),

// Source scripts directory for theme
'paths.theme.src.scripts': (config) =>
path.join(config.get('paths.theme.src'), 'assets', 'scripts'),

// Source snippets directory
'paths.theme.src.snippets': (config) =>
path.join(config.get('paths.theme.src'), 'snippets'),

// Static asset directory for files that statically copied to paths.theme.dist.assets
'paths.theme.src.static': (config) =>
path.join(config.get('paths.theme.src'), 'assets', 'static'),

// Main SVG source directory for theme
'paths.theme.src.svgs': (config) =>
path.join(config.get('paths.theme.src'), 'assets', 'svg'),

// Source liquid template directory
'paths.theme.src.templates': (config) =>
path.join(config.get('paths.theme.src'), 'templates'),

// Source liquid template directory
'paths.theme.src.templates.customers': (config) =>
path.join(config.get('paths.theme.src.templates'), 'customers'),

// Distribution directory of theme
'paths.theme.dist': (config) => path.join(config.get('paths.theme'), 'dist'),

// Distribution assets directory
'paths.theme.dist.assets': (config) =>
path.join(config.get('paths.theme.dist'), 'assets'),

// Distribution assets directory
'paths.theme.dist.config': (config) =>
path.join(config.get('paths.theme.dist'), 'config'),

// Distribution snippets directory
'paths.theme.dist.snippets': (config) =>
path.join(config.get('paths.theme.dist'), 'snippets'),

// Distribution snippets directory
'paths.theme.dist.locales': (config) =>
path.join(config.get('paths.theme.dist'), 'locales'),

// Directory for storing all temporary and/or cache files
'paths.theme.cache': (config) =>
path.join(config.get('paths.theme'), '.cache'),
};
87 changes: 44 additions & 43 deletions packages/slate-config/index.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,56 @@
const path = require('path');
const fs = require('fs');

const themeDirectory = fs.realpathSync(process.cwd());
// Fetch the contents of Slate's user config once, and only once
global.slateUserConfig = global.slateUserConfig || getSlateUserConfig();

function getSlateConfig() {
try {
const slateRcPath = resolveTheme('slate.config.js');
return require(slateRcPath);
} catch (error) {
return {};
}
}

function generate(schema, slaterc = getSlateConfig()) {
// Creates a config object of default or slaterc values
const config = _generateConfig([schema], slaterc)[schema.id];
config.__schema = schema;
module.exports = class SlateConfig {
constructor(schema, userConfigOverride) {
if (typeof schema === 'undefined') {
throw new TypeError(
'[slate-config]: A schema object must be provided as the first argument',
);
}

return config;
}
this.userConfigOverride = userConfigOverride;
this.schema = Object.assign({}, schema, this.userConfig);
}

function _generateConfig(items, overrides) {
const config = {};
get userConfig() {
return typeof this.userConfigOverride === 'object'
? this.userConfigOverride
: global.slateUserConfig;
}

items.forEach((item) => {
if (Array.isArray(item.items)) {
config[item.id] = _generateConfig(
item.items,
overrides && overrides[item.id],
set(key, value, override = false) {
if (typeof this.schema[key] !== 'undefined' && !override) {
throw new Error(
`[slate-config]: A value for '${key}' has already been set. A value can only be set once.`,
);
} else if (overrides && typeof overrides[item.id] !== 'undefined') {
config[item.id] = overrides[item.id];
} else if (typeof item.default !== 'undefined') {
config[item.id] = item.default;
}
});

return config;
}

function resolveTheme(relativePath) {
return path.resolve(themeDirectory, relativePath);
}
this.schema[key] = value;
}

function resolveSelf(relativePath) {
return path.resolve(__dirname, relativePath);
}
get(key) {
const value = this.schema[key];

module.exports = {
generate,
resolveTheme,
resolveSelf,
getSlateConfig,
if (typeof value === 'function') {
// Set the computed value so we don't need to recompute this value multiple times
return (this.schema[key] = value(this));
} else if (typeof value === 'undefined') {
throw new Error(
`[slate-config]: A value has not been defined for the key '${key}'`,
);
} else {
return value;
}
}
};

function getSlateUserConfig() {
try {
return require(path.join(process.cwd(), 'slate.config.js'));
} catch (error) {
return {};
}
}
Loading

0 comments on commit fb117e0

Please sign in to comment.