Files
30-seconds-of-code/node_modules/gatsby/dist/schema/infer/example-value.js
2019-08-20 15:52:05 +02:00

188 lines
5.0 KiB
JavaScript

"use strict";
const _ = require(`lodash`);
const is32BitInteger = require(`./is-32-bit-integer`);
const {
looksLikeADate
} = require(`../types/date`);
const getExampleValue = ({
nodes,
typeName,
typeConflictReporter,
ignoreFields
}) => {
const exampleValue = getExampleObject({
nodes,
prefix: typeName,
typeConflictReporter,
ignoreFields
});
return exampleValue;
};
module.exports = {
getExampleValue
};
const getExampleObject = ({
nodes: rawNodes,
prefix,
typeConflictReporter,
ignoreFields = []
}) => {
const nodes = rawNodes.filter(node => node != null);
const allKeys = nodes.reduce((acc, node) => Object.keys(node).forEach(key => key && !ignoreFields.includes(key) && acc.add(key)) || acc, new Set());
const exampleValue = Array.from(allKeys).reduce((acc, key) => {
const entries = nodes.map(node => {
const value = node[key];
const type = getType(value);
return type && {
value,
type,
parent: node
};
}).filter(Boolean);
const selector = prefix ? `${prefix}.${key}` : key;
const entriesByType = _.uniqBy(entries, entry => entry.type);
if (!entriesByType.length) return acc; // TODO: This whole thing could be prettier!
let {
value,
type
} = entriesByType[0];
let arrayWrappers = 0;
while (Array.isArray(value)) {
value = value.find(v => v != null);
arrayWrappers++;
}
if (entriesByType.length > 1 || type.includes(`,`)) {
if (isMixOfDatesAndStrings(entriesByType.map(entry => entry.type), arrayWrappers)) {
// TODO: Possibly revisit this in Gatsby v3.
const allNonEmptyStringsAreDates = entries.every(entry => {
const values = Array.isArray(entry.value) ? _.flatMap(entry.value) : [entry.value];
return values.every(value => value === `` || getType(value) === `date`);
});
if (allNonEmptyStringsAreDates) {
value = `1978-09-26`;
} else {
value = `String`;
}
} else {
typeConflictReporter.addConflict(selector, entriesByType);
return acc;
}
}
let exampleFieldValue;
if (_.isObject(value) && !_.isArray(value) && !_.isDate(value) && !_.isRegExp(value)) {
const objects = entries.reduce((acc, entry) => {
let {
value
} = entry;
let arrays = arrayWrappers - 1;
while (arrays > 0) {
value = value.find(v => v != null);
arrays--;
}
return acc.concat(value);
}, []);
const exampleObject = getExampleObject({
nodes: objects,
prefix: selector,
typeConflictReporter
});
if (!Object.keys(exampleObject).length) return acc;
exampleFieldValue = exampleObject;
} else if (key.includes(`___NODE`) && arrayWrappers) {
// For arrays on ___NODE foreign-key fields we return all values,
// because the array values are allowed to link to nodes of different types.
// For those we will create a GraphQLUnionType later.
arrayWrappers--;
exampleFieldValue = entries.reduce((acc, entry) => acc.concat(entry.value), []);
} else {
// FIXME: Why not simply treat every number as float (instead of looping through all values again)?
exampleFieldValue = typeof value === `number` && findFloat(entries) || value; // exampleFieldValue = value === `number` ? 0.1 : value
}
while (arrayWrappers--) {
exampleFieldValue = [exampleFieldValue];
}
acc[key] = exampleFieldValue;
return acc;
}, {});
return exampleValue;
};
const isMixOfDatesAndStrings = (types, arrayWrappers) => {
const acc = new Set();
types.every(type => {
let arrays = arrayWrappers;
while (arrays--) {
if (type.startsWith(`[`)) {
type = type.slice(1, -1);
} else {
return false;
}
}
type.split(`,`).forEach(t => acc.add(t.replace(/[[]]/g, ``)));
return true;
});
return acc.size === 2 && acc.has(`date`) && acc.has(`string`);
};
const findFloat = entries => {
let result;
const find = numbers => numbers.some(value => {
const number = typeof value === `object` ? value.value : value;
return Array.isArray(number) ? find(number) : !is32BitInteger(number) && (result = number);
});
find(entries);
return result;
};
const getType = value => {
switch (typeof value) {
case `number`:
return `number`;
case `string`:
return looksLikeADate(value) ? `date` : `string`;
case `boolean`:
return `boolean`;
case `object`:
if (value === null) return null;
if (value instanceof Date) return `date`;
if (value instanceof String) return `string`;
if (Array.isArray(value)) {
const uniqueValues = _.uniq(value.map(getType).filter(v => v != null));
return uniqueValues.length ? `[${uniqueValues.join(`,`)}]` : null;
}
if (!Object.keys(value).length) return null;
return `object`;
default:
return null;
}
};
//# sourceMappingURL=example-value.js.map