Skip to content

Commit

Permalink
Chore: Make tests work
Browse files Browse the repository at this point in the history
  • Loading branch information
nzakas committed Nov 24, 2019
1 parent f22a10c commit 0464990
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 28 deletions.
5 changes: 1 addition & 4 deletions .eslintrc.js
Expand Up @@ -32,10 +32,7 @@ module.exports = {
mocha: true,
commonjs: true,
node: true
},
parserOptions: {
sourceType: "script"
}
}
]
};
};
16 changes: 16 additions & 0 deletions src/base-schema.js
Expand Up @@ -7,12 +7,24 @@
// Helpers
//------------------------------------------------------------------------------

/**
* Assets that a given value is an array.
* @param {*} value The value to check.
* @returns {void}
* @throws {TypeError} When the value is not an array.
*/
function assertIsArray(value) {
if (!Array.isArray(value)) {
throw new TypeError("Expected value to be an array.");
}
}

/**
* Assets that a given value is an array containing only strings.
* @param {*} value The value to check.
* @returns {void}
* @throws {TypeError} When the value is not an array of strings.
*/
function assertIsArrayOfStrings(value, name) {
assertIsArray(value, name);

Expand All @@ -25,6 +37,10 @@ function assertIsArrayOfStrings(value, name) {
// Exports
//------------------------------------------------------------------------------

/**
* The base schema that every ConfigArray uses.
* @type Object
*/
export const baseSchema = Object.freeze({
name: {
required: false,
Expand Down
87 changes: 73 additions & 14 deletions src/config-array.js
Expand Up @@ -24,13 +24,31 @@ const MINIMATCH_OPTIONS = {
matchBase: true
};

function normalize(items, context) {

/**
* Normalizes a `ConfigArray` by flattening it and executing any functions
* that are found inside.
* @param {Array} items The items in a `ConfigArray`.
* @param {Object} context The context object to pass into any function
* found.
* @returns {Array} A flattened array containing only config objects.
* @throws {TypeError} When a config function returns a function.
*/
async function normalize(items, context) {

// TODO: Allow async config functions

function *flatTraverse(array) {
for (const item of array) {
for (let item of array) {
if (typeof item === "function") {
item = item(context);
}

if (Array.isArray(item)) {
yield* flatTraverse(item);
} else {
} else if (typeof item === "function") {
throw new TypeError("A config function can only return an object or array.");
} else {
yield item;
}
}
Expand All @@ -41,12 +59,27 @@ function normalize(items, context) {
return [...flatTraverse(items)];
}


/**
* Determines if a given file path is matched by a config. If the config
* has no `files` field, then it matches; otherwise, if a `files` field
* is present then we match the globs in `files` and exclude any globs in
* `ignores`.
* @param {string} relativeFilePath The file path to check relative to
* the `ConfigArray` `basePath` option.
* @param {Object} config The config object to check.
* @returns {boolean} True if the file path is matched by the config,
* false if not.
*/
function pathMatches(relativeFilePath, config) {

// a config without a `files` field always matches
if (!config.files) {
return true;
}

// check for all matches to config.files
let matches = config.files.some(pattern => {
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS)
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS);
});

/*
Expand All @@ -55,13 +88,19 @@ function pathMatches(relativeFilePath, config) {
*/
if (matches && config.ignores) {
matches = !config.ignores.some(pattern => {
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS)
return minimatch(relativeFilePath, pattern, MINIMATCH_OPTIONS);
});
}

return matches;
}

/**
* Ensures that a ConfigArray has been normalized.
* @param {ConfigArray} configArray The ConfigArray to check.
* @returns {void}
* @throws {Error} When the `ConfigArray` is not normalized.
*/
function assertNormalized(configArray) {
// TODO: Throw more verbose error
if (!configArray.isNormalized()) {
Expand All @@ -74,7 +113,6 @@ function assertNormalized(configArray) {
//------------------------------------------------------------------------------

const isNormalized = Symbol("isNormalized");
const rules = Symbol("rules");
const configCache = Symbol("configCache");
const schema = Symbol("schema");

Expand All @@ -91,10 +129,10 @@ export class ConfigArray extends Array {
* @param {string} [options.basePath=""] The path of the config file
* @param {boolean} [options.normalized=false] Flag indicating if the
* configs have already been normalized.
* @param {Object} [options.schemaDefs] The additional schema
* @param {Object} [options.schema] The additional schema
* definitions to use for the ConfigArray schema.
*/
constructor(configs, { basePath = "", normalized = false, schemaDefs } = {}) {
constructor(configs, { basePath = "", normalized = false, schema: customSchema } = {}) {
super();

/**
Expand All @@ -112,8 +150,8 @@ export class ConfigArray extends Array {
* @private
*/
this[schema] = new ObjectSchema({
...baseSchema,
...schemaDefs
...customSchema,
...baseSchema
});

/**
Expand Down Expand Up @@ -152,6 +190,27 @@ export class ConfigArray extends Array {
return Array;
}

/**
* Returns the `files` globs from every config object in the array.
* This can be used to determine which files will be matched by a
* config array.
* @returns {string[]} An array of string patterns.
*/
get files() {

assertNormalized(this);

const result = [];

for (const config of this) {
if (config.files) {
result.push(...config.files);
}
}

return result;
}

/**
* Returns the file globs that should always be ignored regardless of
* the matching `files` fields in any configs. This is necessary to mimic
Expand Down Expand Up @@ -185,13 +244,13 @@ export class ConfigArray extends Array {
/**
* Normalizes a config array by flattening embedded arrays and executing
* config functions.
* @param {ConfigContext} context The context object for configs.
* @param {ConfigContext} context The context object for config functions.
* @returns {ConfigArray} A new ConfigArray instance that is normalized.
*/
async normalize(context = {}) {

if (!this.isNormalized()) {
const normalizedConfigs = normalize(this);
const normalizedConfigs = await normalize(this, context);
this.length = 0;
this.push(...normalizedConfigs);
this[isNormalized] = true;
Expand Down Expand Up @@ -225,7 +284,7 @@ export class ConfigArray extends Array {
const relativeFilePath = path.relative(this.basePath, filePath);

for (const config of this) {
if (!config.files || pathMatches(relativeFilePath, config)) {
if (pathMatches(relativeFilePath, config)) {
debug(`Matching config found for ${relativeFilePath}`);
matchingConfigs.push(config);
} else {
Expand Down
51 changes: 41 additions & 10 deletions tests/config-array.test.js
Expand Up @@ -20,6 +20,40 @@ const expect = chai.expect;

const basePath = path.dirname(import.meta.url);

const schema = {
language: {
required: false,
validate(value) {
if (typeof value !== "function") {
throw new TypeError("Expected a function.");
}
},
merge(a, b) {
if (!b) {
return a;
}

if (!a) {
return b;
}
}
},
defs: {
required: false,
validate(value) {
if (!value || typeof value !== "object") {
throw new TypeError("Object expected.");
}
},
merge(a, b) {
return {
...a,
...b
};
}
}
};

const JSLanguage = class {};
const CSSLanguage = class {};
const MarkdownLanguage = class {};
Expand All @@ -40,12 +74,11 @@ function createConfigArray() {
language: MarkdownLanguage
}, {
defs: {
ruleNamespaces: {
js: {}
}
name: "config-array"
}
}], {
basePath: path.dirname(import.meta.url)
basePath: path.dirname(import.meta.url),
schema
});
}

Expand All @@ -57,9 +90,9 @@ describe("ConfigArray", () => {

let configs;

beforeEach(() => {
beforeEach(async () => {
configs = createConfigArray();
configs.normalize();
await configs.normalize();
});

describe("getConfig()", () => {
Expand All @@ -71,8 +104,7 @@ describe("ConfigArray", () => {

expect(config.language).to.equal(JSLanguage);
expect(config.defs).to.be.an("object");
expect(config.defs.ruleNamespaces).to.be.an("object");
expect(config.defs.ruleNamespaces.js).to.be.an("object");
expect(config.defs.name).to.equal("config-array");
});

it("should calculate correct config when passed CSS filename", () => {
Expand All @@ -81,8 +113,7 @@ describe("ConfigArray", () => {
const config = configs.getConfig(filename);
expect(config.language).to.equal(CSSLanguage);
expect(config.defs).to.be.an("object");
expect(config.defs.ruleNamespaces).to.be.an("object");
expect(config.defs.ruleNamespaces.js).to.be.an("object");
expect(config.defs.name).to.equal("config-array");

});

Expand Down

0 comments on commit 0464990

Please sign in to comment.