@stackbit/dev-common 1.0.40 → 1.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -164,9 +164,9 @@ export class ContentStoreAdapter {
164
164
  userLogger: this.userLogger
165
165
  });
166
166
  this.stackbitConfig = await this.extendStackbitConfigWithContentSources(stackbitConfig);
167
- if (this.stackbitConfig?.contentSources || this.stackbitConfig?.connectors) {
167
+ if (this.csiEnabled || this.stackbitConfig?.contentSources || this.stackbitConfig?.connectors) {
168
168
  this.userLogger.info('Using Content Source Interface');
169
- const stackbitYamlDir = this.stackbitConfig.dirPath;
169
+ const stackbitYamlDir = this.stackbitConfig?.dirPath || this.appDir;
170
170
  this.contentStore = new ContentStore({
171
171
  logger: this.logger,
172
172
  userLogger: this.userLogger,
@@ -277,7 +277,12 @@ export class ContentStoreAdapter {
277
277
  });
278
278
  await this.contentStore.init({ stackbitConfig: this.stackbitConfig });
279
279
  } else {
280
- this.userLogger.info(`Loading from ${this.cmsType || 'git'}...`);
280
+ this.userLogger.warn(
281
+ `It looks like your stackbit.config.ts doesn't have any 'contentSources' defined. ` +
282
+ 'Add at least one content source to enable visual editing. ' +
283
+ 'For more info please visit https://visual-editor-reference.netlify.com/config'
284
+ );
285
+ this.userLogger.info(`Loading from legacy ${this.cmsType || 'git'}...`);
281
286
  this.cms = this.createCms();
282
287
  await this.cms.run({ spawnRunner: this.userCommandSpawner });
283
288
  }
@@ -326,17 +331,32 @@ export class ContentStoreAdapter {
326
331
  return config;
327
332
  }
328
333
 
329
- // if CSI enabled, and cmsType is one of the CSI supported content-sources,
330
- // create content-sources according to the cmsType
331
- const supportedContentSources = ['git', 'contentful', 'sanity'];
332
- const forceCSI = (!this.cmsType || supportedContentSources.includes(this.cmsType)) && this.csiEnabled;
333
- if (!forceCSI) {
334
+ // If CSI is not enabled, return unmodified config
335
+ if (!this.csiEnabled) {
336
+ return config;
337
+ }
338
+
339
+ const cmsType = this.cmsType || config.cmsName;
340
+
341
+ if (!cmsType) {
334
342
  return config;
335
343
  }
336
344
 
345
+ // If CSI is enabled, and cmsType is one of the supported content-sources,
346
+ // install and instantiate a content-sources based on the cmsType.
347
+ const supportedContentSources = ['git', 'contentful', 'sanity'];
348
+ if (supportedContentSources.includes(cmsType)) {
349
+ this.userLogger.warn('No content sources defined in stackbit config!');
350
+ this.userLogger.warn(`Installing and instantiating content source based on the provided CMS type: '${cmsType}'`);
351
+ }
352
+
337
353
  // for backward compatibility use ContentfulContentSource when stackbit.yaml has cmsType === 'contentful'
338
- if (this.cmsType === 'contentful') {
339
- const contentfulContentSourceModule = await importContentSourceModule('@stackbit/cms-contentful');
354
+ if (cmsType === 'contentful') {
355
+ const contentfulContentSourceModule = await installAndImportContentSourceModule({
356
+ packageName: '@stackbit/cms-contentful',
357
+ projectDir: this.projectDir,
358
+ userLogger: this.userLogger
359
+ });
340
360
  const contentSources = this.contentfulSpaces!.map((space) => {
341
361
  return new (contentfulContentSourceModule.ContentfulContentSource as typeof ContentfulContentSource)({
342
362
  spaceId: space.spaceId,
@@ -351,12 +371,16 @@ export class ContentStoreAdapter {
351
371
  }
352
372
 
353
373
  // for backward compatibility use SanityContentSource when stackbit.yaml has cmsType === 'sanity'
354
- if (this.cmsType === 'sanity') {
374
+ if (cmsType === 'sanity') {
355
375
  if (!this.sanityProject) {
356
376
  this.userLogger.error('Cannot create SanityContentSource, missing sanity project data');
357
377
  throw new Error('Cannot create SanityContentSource, missing sanity project data');
358
378
  }
359
- const sanityContentSourceModule = await importContentSourceModule('@stackbit/cms-sanity');
379
+ const sanityContentSourceModule = await installAndImportContentSourceModule({
380
+ packageName: '@stackbit/cms-sanity',
381
+ projectDir: this.projectDir,
382
+ userLogger: this.userLogger
383
+ });
360
384
  const contentSources = [
361
385
  new (sanityContentSourceModule.SanityContentSource as typeof SanityContentSource)({
362
386
  token: this.sanityProject.token,
@@ -373,8 +397,12 @@ export class ContentStoreAdapter {
373
397
  };
374
398
  }
375
399
 
376
- if (!this.cmsType || this.cmsType === 'git') {
377
- const gitContentSourceModule = await importContentSourceModule('@stackbit/cms-git');
400
+ if (cmsType === 'git') {
401
+ const gitContentSourceModule = await installAndImportContentSourceModule({
402
+ packageName: '@stackbit/cms-git',
403
+ projectDir: this.projectDir,
404
+ userLogger: this.userLogger
405
+ });
378
406
  const result = await loadConfigWithModelsPresetsAndValidate({
379
407
  dirPath: this.projectDir,
380
408
  isForcedGitCSI: true
@@ -396,11 +424,9 @@ export class ContentStoreAdapter {
396
424
  };
397
425
  }
398
426
 
399
- throw new Error(`no default content source for cmsType: ${this.cmsType}`);
400
-
401
- // for backward compatibility use ContentfulContentSource when stackbit.yaml has cmsType === 'git'
402
- // const gitContentSourceModule = await importContentSourceModule('@stackbit/cms-git');
403
- // return ...
427
+ // If CSI is enabled, but there is no cmsType, or the cmsType doesn't
428
+ // match any of the supported content-sources, return unmodified config.
429
+ return config;
404
430
  }
405
431
 
406
432
  private createCms(): CMSInterface {
@@ -1303,18 +1329,31 @@ export class ContentStoreAdapter {
1303
1329
  }
1304
1330
  }
1305
1331
 
1306
- async function importContentSourceModule(packageName: string) {
1332
+ async function installAndImportContentSourceModule({ packageName, projectDir, userLogger }: { packageName: string; projectDir: string; userLogger: Logger }) {
1333
+ try {
1334
+ userLogger.info(`Installing ${packageName}...`);
1335
+ const runCommand = getCommandRunner({ env: process.env });
1336
+ await runCommand('npm', ['install', packageName, '--no-save'], {
1337
+ env: process.env,
1338
+ cwd: projectDir,
1339
+ logger: userLogger
1340
+ });
1341
+ } catch (error: any) {
1342
+ userLogger.error(`Error installing ${packageName}, error: ${error.message}`);
1343
+ throw new Error(`Error installing ${packageName}, please add it as a devDependency to your project by running "npm i ${packageName} --save-dev"`);
1344
+ }
1345
+
1307
1346
  let modulePath;
1308
1347
  try {
1309
1348
  modulePath = require.resolve(packageName);
1310
1349
  } catch (error) {
1311
- throw new Error(`can not find ${packageName} package, please add it as a devDependency by running "npm i ${packageName} --save-dev"`);
1350
+ throw new Error(`Can not find ${packageName} package, please add it as a devDependency to your project by running "npm i ${packageName} --save-dev"`);
1312
1351
  }
1313
1352
  let module;
1314
1353
  try {
1315
1354
  module = await import(modulePath);
1316
1355
  } catch (error: any) {
1317
- throw new Error(`could not load ${packageName} module, error: ${error.message}`);
1356
+ throw new Error(`Could not load ${packageName} module, error: ${error.message}`);
1318
1357
  }
1319
1358
  return module;
1320
1359
  }
@@ -1,7 +1,8 @@
1
1
  const _ = require('lodash');
2
2
  const chalk = require('chalk');
3
+ const { fieldPathToString } = require('@stackbit/utils');
3
4
  const { forEachField } = require('../../utils/code-utils');
4
- const { fieldPathToString, fieldPathToFieldDataPath, appendOrArray } = require('./annotation-utils');
5
+ const { fieldPathToFieldDataPath, appendOrArray } = require('./annotation-utils');
5
6
  const REGEX_ENDS_WITH_TEXT_PATH = /text\(\)(\[\d*\])?$/;
6
7
  const ANNOTATION_XPATH_SELF = ['self::node()', '.'];
7
8
  const ANNOTATION_ERROR = 'AnnotationError';
@@ -1,4 +1,5 @@
1
1
  const _ = require('lodash');
2
+ const { fieldPathToString } = require('@stackbit/utils');
2
3
 
3
4
  /**
4
5
  * This method translates fieldPath (object.sections[0].title) to fieldDataPath (object.fields.sections.items[0].fields.title)
@@ -71,38 +72,11 @@ function fieldPathToFieldDataPath(objectId, fieldPathStr, getObjectById) {
71
72
  return { fieldDataPath, fieldDataPathStr: fieldPathToString(fieldDataPath), fieldDataPathsFromRoot };
72
73
  }
73
74
 
74
- /**
75
- * This converts a fieldPath array to a string, it puts complex strings inside single quotes '', and uses square brackets [] for number keys.
76
- * @param fieldPath
77
- * @returns {*}
78
- */
79
- function fieldPathToString(fieldPath) {
80
- return _.reduce(
81
- fieldPath,
82
- (accumulator, fieldName, index) => {
83
- if (_.isString(fieldName) && /\W/.test(fieldName)) {
84
- // field name is a string with non alphanumeric character
85
- accumulator += `['${fieldName}']`;
86
- } else if (_.isNumber(fieldName)) {
87
- accumulator += `[${fieldName}]`;
88
- } else {
89
- if (index > 0) {
90
- accumulator += '.';
91
- }
92
- accumulator += fieldName;
93
- }
94
- return accumulator;
95
- },
96
- ''
97
- );
98
- }
99
-
100
75
  function appendOrArray(object, path, item) {
101
76
  _.set(object, path, [..._.get(object, path, []), item]);
102
77
  }
103
78
 
104
79
  module.exports = {
105
80
  fieldPathToFieldDataPath,
106
- fieldPathToString,
107
81
  appendOrArray
108
82
  };