@stackbit/sdk
Version:
120 lines • 5.77 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getModelsByQuery = exports.getModelByQuery = void 0;
const micromatch_1 = __importDefault(require("micromatch"));
const lodash_1 = __importDefault(require("lodash"));
const content_errors_1 = require("../content/content-errors");
/**
* Returns a single model matching the `query` describing a content file.
* @see `getModelsByQuery()` for more info.
*
* @param {Object} query A query object to match a model against.
* @param {string} query.filePath The path of the content file relative to the `pagesDir` or `dataDir` folders defined in stackbit.yaml.
* @param {string} [query.type] The type of the data file. For example, can be page's layout that maps to page's model.
* @param {Array|string} [query.modelTypeKeyPath] Used to compare the value of `query.type` with the value of a model at `modelTypeKeyPath`.
* Required if `query.type` is provided.
* @param {Array.<Object>} models Array of stackbit.yaml `models`.
* @return {Object} stackbit.yaml model matching the `query`.
*/
function getModelByQuery(query, models) {
const matchedModels = getModelsByQuery(query, models);
const filePath = lodash_1.default.get(query, 'filePath');
if (matchedModels.length === 0) {
return { model: null, error: new content_errors_1.FileNotMatchedModelError({ filePath: filePath }) };
}
else if (matchedModels.length > 1) {
return { model: null, error: new content_errors_1.FileMatchedMultipleModelsError({ filePath: filePath, modelNames: lodash_1.default.map(matchedModels, 'name') }) };
}
return { model: matchedModels[0], error: null };
}
exports.getModelByQuery = getModelByQuery;
/**
* Returns an array of models matching the `query` describing a content file.
*
* The `query` object is required to have the `filePath` property which is the path
* of the content file relative to the `pagesDir` or `dataDir` folders defined
* in stackbit.yaml.
*
* The `query` object might also contain the `type` and `modelTypeKeyPath`
* properties. When these properties provided, the value of the `type` is
* compared against the value of a model located at the path specified by
* `modelTypeKeyPath`. This is useful, when a folder might contain objects of
* different model types.
*
* @param {Object} query A query object to match models against.
* @param {string} query.filePath The path of the content file relative to the `pagesDir` or `dataDir` folders defined in stackbit.yaml.
* @param {string} [query.type] The type of the data file. For example, can be page's layout that maps to page's model.
* @param {Array|string} [query.modelTypeKeyPath] Used to compare the value of `query.type` with the value of a model at `modelTypeKeyPath`.
* Required if `query.type` is provided.
* @param {Array.<Object>} models Array of stackbit.yaml `models`.
* @return {Array.<Model>} Array of stackbit.yaml models matching the `query`.
*/
function getModelsByQuery(query, models) {
const filePath = lodash_1.default.get(query, 'filePath');
const objectType = lodash_1.default.get(query, 'type');
const modelTypeKeyPath = lodash_1.default.get(query, 'modelTypeKeyPath');
const modelMatchGroups = lodash_1.default.reduce(models, (modelGroups, model) => {
if (lodash_1.default.has(model, 'file')) {
modelGroups.byFile.push(model);
}
else if (objectType && lodash_1.default.has(model, modelTypeKeyPath)) {
modelGroups.byType.push(model);
}
else {
modelGroups.byGlob.push(model);
}
return modelGroups;
}, {
byFile: [],
byType: [],
byGlob: []
});
const fileMatchedModels = lodash_1.default.filter(modelMatchGroups.byFile, (model) => {
if (!('file' in model) || !lodash_1.default.isString(model.file)) {
return false;
}
try {
return micromatch_1.default.isMatch(filePath, model.file);
}
catch (error) {
return false;
}
});
if (!lodash_1.default.isEmpty(fileMatchedModels)) {
return fileMatchedModels;
}
const typeMatchedModels = lodash_1.default.filter(modelMatchGroups.byType, (model) => {
const modelType = lodash_1.default.get(model, modelTypeKeyPath);
return objectType === modelType;
});
if (!lodash_1.default.isEmpty(typeMatchedModels)) {
return typeMatchedModels;
}
return lodash_1.default.filter(modelMatchGroups.byGlob, (model) => {
const folder = lodash_1.default.get(model, 'folder', '');
let match = lodash_1.default.get(model, 'match', '**/*');
let exclude = lodash_1.default.get(model, 'exclude', []);
match = joinPathAndGlob(folder, match);
exclude = joinPathAndGlob(folder, exclude);
return micromatch_1.default.isMatch(filePath, match) && (lodash_1.default.isEmpty(exclude) || !micromatch_1.default.isMatch(filePath, exclude));
});
}
exports.getModelsByQuery = getModelsByQuery;
function joinPathAndGlob(pathStr, glob) {
glob = globToArray(glob);
return lodash_1.default.map(glob, (globPart) => lodash_1.default.compact([pathStr, globPart]).join('/'));
}
function globToArray(glob) {
return lodash_1.default.chain(glob)
.castArray()
.compact()
.reduce((accum, globPart) => {
const globParts = lodash_1.default.chain(globPart).trim('{}').split(',').compact().value();
return lodash_1.default.concat(accum, globParts);
}, [])
.value();
}
//# sourceMappingURL=model-matcher.js.map