Socket
Socket
Sign inDemoInstall

@stackbit/sdk

Package Overview
Dependencies
Maintainers
18
Versions
404
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@stackbit/sdk - npm Package Compare versions

Comparing version 0.2.23 to 0.2.24

5

dist/config/config-loader.d.ts
import { ConfigError, ConfigLoadError, ConfigValidationError } from './config-errors';
import { Config } from './config-types';
import { Config, Model } from './config-types';
export interface ConfigLoaderOptions {
[option: string]: any;
dirPath: string;
modelsSource?: string;
}

@@ -22,2 +23,2 @@ export interface ConfigLoaderResult {

export declare function loadConfig({ dirPath, ...options }: ConfigLoaderOptions): Promise<ConfigLoaderResult>;
export declare function validateAndNormalizeConfig(config: any): NormalizedValidationResult;
export declare function validateAndNormalizeConfig(config: any, externalModels?: Model[]): NormalizedValidationResult;

160

dist/config/config-loader.js

@@ -37,23 +37,12 @@ "use strict";

async function loadConfig({ dirPath, ...options }) {
let configLoadResult;
try {
configLoadResult = await loadConfigFromDir(dirPath);
}
catch (error) {
const { config, errors: configLoadErrors } = await loadConfigFromDir(dirPath);
if (!config) {
return {
valid: false,
config: null,
errors: [new config_errors_1.ConfigLoadError(`Error loading Stackbit configuration: ${error.message}`, { originalError: error })]
errors: configLoadErrors
};
}
if (!configLoadResult.config) {
return {
valid: false,
config: null,
errors: configLoadResult.errors
};
}
const externalModelsResult = await loadModelsFromExternalSource(configLoadResult.config, options);
const mergedConfig = mergeConfigWithExternalModels(configLoadResult.config, externalModelsResult.models);
const normalizedResult = validateAndNormalizeConfig(mergedConfig);
const { models: externalModels, errors: externalModelsLoadErrors } = await loadModelsFromExternalSource(config, dirPath, options);
const normalizedResult = validateAndNormalizeConfig(config, externalModels);
const presetsResult = await presets_loader_1.loadPresets(dirPath, normalizedResult.config);

@@ -63,25 +52,28 @@ return {

config: presetsResult.config,
errors: [...configLoadResult.errors, ...externalModelsResult.errors, ...normalizedResult.errors, ...presetsResult.errors]
errors: [...configLoadErrors, ...externalModelsLoadErrors, ...normalizedResult.errors, ...presetsResult.errors]
};
}
exports.loadConfig = loadConfig;
function validateAndNormalizeConfig(config) {
function validateAndNormalizeConfig(config, externalModels) {
// extend config models having the "extends" property
// this must be done before any validation as some properties like
// the labelField will not work when validating models without extending them first
const { models: extendedModels, errors: extendModelErrors } = utils_1.extendModelMap(config.models);
const extendedConfig = {
...config,
models: extendedModels
};
const { config: mergedConfig, errors: externalModelsMergeErrors } = mergeConfigWithExternalModels(extendedConfig, externalModels);
// validate the "contentModels" and extend config models with "contentModels"
// this must be done before main config validation to make it independent of "contentModels".
const contentModelsValidationResult = validateAndExtendContentModels(config);
config = contentModelsValidationResult.value;
// extend config models having the "extends" property
// this must be done before main config validation as some properties like
// the labelField will not work when validating models without extending them first
const { models, errors: extendModelErrors } = utils_1.extendModelMap((config === null || config === void 0 ? void 0 : config.models) || {});
config.models = models;
const { value: configWithContentModels, errors: contentModelsErrors } = validateAndExtendContentModels(mergedConfig);
// normalize config - backward compatibility updates, adding extra fields like "markdown_content", "type" and "layout",
// and setting other default values.
config = normalizeConfig(config);
const normalizedConfig = normalizeConfig(configWithContentModels);
// validate config
const configValidationResult = config_validator_1.validateConfig(config);
const errors = [...contentModelsValidationResult.errors, ...extendModelErrors, ...configValidationResult.errors];
const { value: validatedConfig, errors: validationErrors } = config_validator_1.validateConfig(normalizedConfig);
const errors = [...extendModelErrors, ...externalModelsMergeErrors, ...contentModelsErrors, ...validationErrors];
return normalizeValidationResult({
valid: lodash_1.default.isEmpty(errors),
value: configValidationResult.value,
value: validatedConfig,
errors: errors

@@ -92,9 +84,23 @@ });

async function loadConfigFromDir(dirPath) {
const { config, error } = await loadConfigFromStackbitYaml(dirPath);
if (error) {
return { errors: [error] };
var _a;
try {
const { config, error } = await loadConfigFromStackbitYaml(dirPath);
if (error) {
return { errors: [error] };
}
const { models: modelsFromFiles, errors: fileModelsErrors } = await loadModelsFromFiles(dirPath, config);
const mergedModels = mergeConfigModelsWithModelsFromFiles((_a = config.models) !== null && _a !== void 0 ? _a : {}, modelsFromFiles);
return {
config: {
...config,
models: mergedModels
},
errors: fileModelsErrors
};
}
const modelsFromFileResult = await loadModelsFromFiles(dirPath, config);
const mergedConfig = mergeConfigModelsWithModelsFromFiles(config, modelsFromFileResult.models);
return { config: mergedConfig, errors: modelsFromFileResult.errors };
catch (error) {
return {
errors: [new config_errors_1.ConfigLoadError(`Error loading Stackbit configuration: ${error.message}`, { originalError: error })]
};
}
}

@@ -170,5 +176,6 @@ async function loadConfigFromStackbitYaml(dirPath) {

}
async function loadModelsFromExternalSource(config, options) {
async function loadModelsFromExternalSource(config, dirPath, options) {
var _a;
const modelsSource = lodash_1.default.get(config, 'modelsSource', {});
const sourceType = lodash_1.default.get(modelsSource, 'type', 'files');
const sourceType = (_a = options.modelsSource) !== null && _a !== void 0 ? _a : lodash_1.default.get(modelsSource, 'type', 'files');
if (sourceType === 'files') {

@@ -179,3 +186,4 @@ return { models: [], errors: [] };

const contentfulModule = lodash_1.default.get(modelsSource, 'module', '@stackbit/cms-contentful');
const module = await Promise.resolve().then(() => __importStar(require(contentfulModule)));
const modulePath = path_1.default.join(dirPath, 'node_modules', contentfulModule);
const module = await Promise.resolve().then(() => __importStar(require(modulePath)));
try {

@@ -228,5 +236,3 @@ const { models } = await module.fetchAndConvertSchema(options);

}
function mergeConfigModelsWithModelsFromFiles(config, modelsFromFiles) {
var _a;
const configModels = (_a = config.models) !== null && _a !== void 0 ? _a : {};
function mergeConfigModelsWithModelsFromFiles(configModels, modelsFromFiles) {
const mergedModels = lodash_1.default.mapValues(modelsFromFiles, (modelFromFile, modelName) => {

@@ -249,3 +255,3 @@ var _a, _b, _c;

});
const configModel = configModels[modelName];
const configModel = lodash_1.default.get(configModels, modelName);
if (!configModel) {

@@ -258,6 +264,3 @@ return modelFromFile;

});
return {
...config,
models: Object.assign({}, configModels, mergedModels)
};
return Object.assign({}, configModels, mergedModels);
}

@@ -267,21 +270,26 @@ function mergeConfigWithExternalModels(config, externalModels) {

if (!externalModels || externalModels.length === 0) {
return config;
return {
config,
errors: []
};
}
const stackbitModels = (_a = config === null || config === void 0 ? void 0 : config.models) !== null && _a !== void 0 ? _a : {};
externalModels = externalModels.map((externalModel) => {
var _a;
const stackbitModel = stackbitModels[externalModel.name];
if (!stackbitModel) {
return externalModel;
const errors = [];
const models = lodash_1.default.reduce(externalModels, (modelMap, externalModel) => {
const { name, ...rest } = externalModel;
return Object.assign(modelMap, { [name]: rest });
}, {});
lodash_1.default.forEach(stackbitModels, (stackbitModel, modelName) => {
var _a, _b;
let externalModel = models[modelName];
if (!externalModel) {
return;
}
const modelType = stackbitModel.type ? (stackbitModel.type === 'config' ? 'data' : stackbitModel.type) : 'object';
const urlPath = modelType === 'page' ? (_a = stackbitModel === null || stackbitModel === void 0 ? void 0 : stackbitModel.urlPath) !== null && _a !== void 0 ? _a : '/{slug}' : null;
const fieldGroups = stackbitModel === null || stackbitModel === void 0 ? void 0 : stackbitModel.fieldGroups;
externalModel = Object.assign(externalModel, utils_2.omitByNil({
__metadata: stackbitModel.__metadata,
const modelType = stackbitModel.type ? (stackbitModel.type === 'config' ? 'data' : stackbitModel.type) : (_a = externalModel.type) !== null && _a !== void 0 ? _a : 'object';
const urlPath = modelType === 'page' ? (_b = stackbitModel === null || stackbitModel === void 0 ? void 0 : stackbitModel.urlPath) !== null && _b !== void 0 ? _b : '/{slug}' : null;
externalModel = Object.assign({}, externalModel, lodash_1.default.pick(stackbitModel, ['__metadata', 'label', 'description', 'thumbnail', 'singleInstance', 'readOnly', 'labelField', 'fieldGroups']), utils_2.omitByNil({
type: modelType,
urlPath,
fieldGroups
urlPath
}));
return utils_1.mapModelFieldsRecursively(externalModel, (field, modelKeyPath) => {
externalModel = utils_1.mapModelFieldsRecursively(externalModel, (field, modelKeyPath) => {
const stackbitField = utils_1.getModelFieldForModelKeyPath(stackbitModel, modelKeyPath);

@@ -291,20 +299,28 @@ if (!stackbitField) {

}
const group = 'group' in stackbitField ? stackbitField.group : null;
const controlType = 'controlType' in stackbitField ? stackbitField.controlType : null;
let override = {};
if ((stackbitField === null || stackbitField === void 0 ? void 0 : stackbitField.type) === 'style') {
if (stackbitField.type === 'style') {
override = stackbitField;
}
return Object.assign({}, field, utils_2.omitByNil({
group,
controlType
}), override);
else if (field.type === 'enum') {
override = lodash_1.default.pick(stackbitField, ['options']);
}
else if (field.type === 'color') {
override = { type: 'color' };
}
else if (field.type === 'number') {
override = lodash_1.default.pick(stackbitField, ['subtype', 'min', 'max', 'step', 'unit']);
}
else if (field.type === 'object') {
override = lodash_1.default.pick(stackbitField, ['labelField', 'thumbnail', 'fieldGroups']);
}
return Object.assign({}, field, lodash_1.default.pick(stackbitField, ['label', 'description', 'required', 'default', 'group', 'const', 'hidden', 'readOnly', 'controlType']), override);
});
models[modelName] = externalModel;
});
return {
...config,
models: lodash_1.default.mapValues(lodash_1.default.keyBy(externalModels, 'name'), (model) => {
lodash_1.default.unset(model, 'name');
return model;
})
config: {
...config,
models: models
},
errors: errors
};

@@ -311,0 +327,0 @@ }

{
"name": "@stackbit/sdk",
"version": "0.2.23",
"version": "0.2.24",
"description": "Stackbit SDK",

@@ -5,0 +5,0 @@ "main": "dist/index.js",

@@ -35,2 +35,3 @@ import path from 'path';

dirPath: string;
modelsSource?: string;
}

@@ -56,27 +57,16 @@

export async function loadConfig({ dirPath, ...options }: ConfigLoaderOptions): Promise<ConfigLoaderResult> {
let configLoadResult: TempConfigLoaderResult;
try {
configLoadResult = await loadConfigFromDir(dirPath);
} catch (error) {
return {
valid: false,
config: null,
errors: [new ConfigLoadError(`Error loading Stackbit configuration: ${error.message}`, { originalError: error })]
};
}
const { config, errors: configLoadErrors } = await loadConfigFromDir(dirPath);
if (!configLoadResult.config) {
if (!config) {
return {
valid: false,
config: null,
errors: configLoadResult.errors
errors: configLoadErrors
};
}
const externalModelsResult = await loadModelsFromExternalSource(configLoadResult.config, options);
const { models: externalModels, errors: externalModelsLoadErrors } = await loadModelsFromExternalSource(config, dirPath, options);
const mergedConfig = mergeConfigWithExternalModels(configLoadResult.config, externalModelsResult.models);
const normalizedResult = validateAndNormalizeConfig(config, externalModels);
const normalizedResult = validateAndNormalizeConfig(mergedConfig);
const presetsResult = await loadPresets(dirPath, normalizedResult.config);

@@ -87,29 +77,34 @@

config: presetsResult.config,
errors: [...configLoadResult.errors, ...externalModelsResult.errors, ...normalizedResult.errors, ...presetsResult.errors]
errors: [...configLoadErrors, ...externalModelsLoadErrors, ...normalizedResult.errors, ...presetsResult.errors]
};
}
export function validateAndNormalizeConfig(config: any): NormalizedValidationResult {
export function validateAndNormalizeConfig(config: any, externalModels?: Model[]): NormalizedValidationResult {
// extend config models having the "extends" property
// this must be done before any validation as some properties like
// the labelField will not work when validating models without extending them first
const { models: extendedModels, errors: extendModelErrors } = extendModelMap(config.models as any);
const extendedConfig = {
...config,
models: extendedModels
};
const { config: mergedConfig, errors: externalModelsMergeErrors } = mergeConfigWithExternalModels(extendedConfig, externalModels);
// validate the "contentModels" and extend config models with "contentModels"
// this must be done before main config validation to make it independent of "contentModels".
const contentModelsValidationResult = validateAndExtendContentModels(config);
config = contentModelsValidationResult.value;
const { value: configWithContentModels, errors: contentModelsErrors } = validateAndExtendContentModels(mergedConfig);
// extend config models having the "extends" property
// this must be done before main config validation as some properties like
// the labelField will not work when validating models without extending them first
const { models, errors: extendModelErrors } = extendModelMap(config?.models || {});
config.models = models;
// normalize config - backward compatibility updates, adding extra fields like "markdown_content", "type" and "layout",
// and setting other default values.
config = normalizeConfig(config);
const normalizedConfig = normalizeConfig(configWithContentModels);
// validate config
const configValidationResult = validateConfig(config);
const { value: validatedConfig, errors: validationErrors } = validateConfig(normalizedConfig);
const errors = [...contentModelsValidationResult.errors, ...extendModelErrors, ...configValidationResult.errors];
const errors = [...extendModelErrors, ...externalModelsMergeErrors, ...contentModelsErrors, ...validationErrors];
return normalizeValidationResult({
valid: _.isEmpty(errors),
value: configValidationResult.value,
value: validatedConfig,
errors: errors

@@ -120,9 +115,24 @@ });

async function loadConfigFromDir(dirPath: string): Promise<TempConfigLoaderResult> {
const { config, error } = await loadConfigFromStackbitYaml(dirPath);
if (error) {
return { errors: [error] };
try {
const { config, error } = await loadConfigFromStackbitYaml(dirPath);
if (error) {
return { errors: [error] };
}
const { models: modelsFromFiles, errors: fileModelsErrors } = await loadModelsFromFiles(dirPath, config);
const mergedModels = mergeConfigModelsWithModelsFromFiles(config.models ?? {}, modelsFromFiles);
return {
config: {
...config,
models: mergedModels
},
errors: fileModelsErrors
};
} catch (error) {
return {
errors: [new ConfigLoadError(`Error loading Stackbit configuration: ${error.message}`, { originalError: error })]
};
}
const modelsFromFileResult = await loadModelsFromFiles(dirPath, config);
const mergedConfig = mergeConfigModelsWithModelsFromFiles(config, modelsFromFileResult.models);
return { config: mergedConfig, errors: modelsFromFileResult.errors };
}

@@ -214,5 +224,9 @@

async function loadModelsFromExternalSource(config: any, options: any): Promise<{ models: Model[]; errors: ConfigLoadError[] }> {
async function loadModelsFromExternalSource(
config: any,
dirPath: string,
options: Omit<ConfigLoaderOptions, 'dirPath'>
): Promise<{ models: Model[]; errors: ConfigLoadError[] }> {
const modelsSource = _.get(config, 'modelsSource', {});
const sourceType = _.get(modelsSource, 'type', 'files');
const sourceType = options.modelsSource ?? _.get(modelsSource, 'type', 'files');
if (sourceType === 'files') {

@@ -222,3 +236,4 @@ return { models: [], errors: [] };

const contentfulModule = _.get(modelsSource, 'module', '@stackbit/cms-contentful');
const module = await import(contentfulModule);
const modulePath = path.join(dirPath, 'node_modules', contentfulModule);
const module = await import(modulePath);
try {

@@ -277,4 +292,3 @@ const { models } = await module.fetchAndConvertSchema(options);

function mergeConfigModelsWithModelsFromFiles(config: any, modelsFromFiles: Record<string, any>) {
const configModels = config.models ?? {};
function mergeConfigModelsWithModelsFromFiles(configModels: any, modelsFromFiles: Record<string, any>) {
const mergedModels = _.mapValues(modelsFromFiles, (modelFromFile, modelName) => {

@@ -296,3 +310,3 @@ // resolve thumbnails of models loaded from files

const configModel = configModels[modelName];
const configModel = _.get(configModels, modelName);
if (!configModel) {

@@ -306,36 +320,45 @@ return modelFromFile;

});
return {
...config,
models: Object.assign({}, configModels, mergedModels)
};
return Object.assign({}, configModels, mergedModels);
}
function mergeConfigWithExternalModels(config: any, externalModels?: Model[]) {
function mergeConfigWithExternalModels(config: any, externalModels?: Model[]): { config: any; errors: ConfigValidationError[] } {
if (!externalModels || externalModels.length === 0) {
return config;
return {
config,
errors: []
};
}
const stackbitModels = config?.models ?? {};
const errors: ConfigValidationError[] = [];
externalModels = externalModels.map((externalModel) => {
const stackbitModel = stackbitModels[externalModel.name];
if (!stackbitModel) {
return externalModel;
const models = _.reduce(
externalModels,
(modelMap: Record<string, YamlModel>, externalModel) => {
const { name, ...rest } = externalModel;
return Object.assign(modelMap, { [name]: rest });
},
{}
);
_.forEach(stackbitModels, (stackbitModel: any, modelName: any) => {
let externalModel = models[modelName];
if (!externalModel) {
return;
}
const modelType = stackbitModel.type ? (stackbitModel.type === 'config' ? 'data' : stackbitModel.type) : 'object';
const modelType = stackbitModel.type ? (stackbitModel.type === 'config' ? 'data' : stackbitModel.type) : externalModel.type ?? 'object';
const urlPath = modelType === 'page' ? stackbitModel?.urlPath ?? '/{slug}' : null;
const fieldGroups = stackbitModel?.fieldGroups;
externalModel = Object.assign(
{},
externalModel,
_.pick(stackbitModel, ['__metadata', 'label', 'description', 'thumbnail', 'singleInstance', 'readOnly', 'labelField', 'fieldGroups']),
omitByNil({
__metadata: stackbitModel.__metadata,
type: modelType,
urlPath,
fieldGroups
urlPath
})
);
return mapModelFieldsRecursively(externalModel, (field, modelKeyPath) => {
externalModel = mapModelFieldsRecursively(externalModel as Model, (field, modelKeyPath) => {
const stackbitField = getModelFieldForModelKeyPath(stackbitModel, modelKeyPath);

@@ -346,8 +369,13 @@ if (!stackbitField) {

const group = 'group' in stackbitField ? stackbitField.group : null;
const controlType = 'controlType' in stackbitField ? stackbitField.controlType : null;
let override = {};
if (stackbitField?.type === 'style') {
if (stackbitField.type === 'style') {
override = stackbitField;
} else if (field.type === 'enum') {
override = _.pick(stackbitField, ['options']);
} else if (field.type === 'color') {
override = { type: 'color' };
} else if (field.type === 'number') {
override = _.pick(stackbitField, ['subtype', 'min', 'max', 'step', 'unit']);
} else if (field.type === 'object') {
override = _.pick(stackbitField, ['labelField', 'thumbnail', 'fieldGroups']);
}

@@ -358,17 +386,16 @@

field,
omitByNil({
group,
controlType
}),
_.pick(stackbitField, ['label', 'description', 'required', 'default', 'group', 'const', 'hidden', 'readOnly', 'controlType']),
override
);
});
}) as YamlModel;
models[modelName] = externalModel;
});
return {
...config,
models: _.mapValues(_.keyBy(externalModels, 'name'), (model) => {
_.unset(model, 'name');
return model;
})
config: {
...config,
models: models
},
errors: errors
};

@@ -375,0 +402,0 @@ }

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc