@storybook/core-server 7.0.0-alpha.4 → 7.0.0-alpha.7

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.
@@ -11,8 +11,6 @@ require("core-js/modules/es.promise.js");
11
11
 
12
12
  var _chalk = _interopRequireDefault(require("chalk"));
13
13
 
14
- var _cpy = _interopRequireDefault(require("cpy"));
15
-
16
14
  var _fsExtra = _interopRequireDefault(require("fs-extra"));
17
15
 
18
16
  var _path = _interopRequireWildcard(require("path"));
@@ -90,7 +88,7 @@ async function buildStaticStandalone(options) {
90
88
  }
91
89
 
92
90
  await _fsExtra.default.emptyDir(options.outputDir);
93
- await (0, _cpy.default)(defaultFavIcon, options.outputDir);
91
+ await _fsExtra.default.copyFile(defaultFavIcon, _path.default.join(options.outputDir, _path.default.basename(defaultFavIcon)));
94
92
 
95
93
  var _await$import = await Promise.resolve().then(function () {
96
94
  return _interopRequireWildcard(require('@storybook/manager-webpack5/prebuilt-manager'));
@@ -168,7 +166,8 @@ async function buildStaticStandalone(options) {
168
166
  initializedStoryIndexGenerator = generator.initialize().then(function () {
169
167
  return generator;
170
168
  });
171
- extractTasks.push((0, _storiesJson.extractStoriesJson)(_path.default.join(options.outputDir, 'stories.json'), initializedStoryIndexGenerator));
169
+ extractTasks.push((0, _storiesJson.extractStoriesJson)(_path.default.join(options.outputDir, 'stories.json'), initializedStoryIndexGenerator, _storiesJson.convertToIndexV3));
170
+ extractTasks.push((0, _storiesJson.extractStoriesJson)(_path.default.join(options.outputDir, 'index.json'), initializedStoryIndexGenerator));
172
171
  }
173
172
 
174
173
  var core = await presets.apply('core');
@@ -182,7 +181,7 @@ async function buildStaticStandalone(options) {
182
181
  var storyIndex = await generator.getIndex();
183
182
  var payload = storyIndex ? {
184
183
  storyIndex: {
185
- storyCount: Object.keys(storyIndex.stories).length,
184
+ storyCount: Object.keys(storyIndex.entries).length,
186
185
  version: storyIndex.v
187
186
  }
188
187
  } : undefined;
@@ -209,9 +208,8 @@ async function buildStaticStandalone(options) {
209
208
  var prebuiltDir = await getPrebuiltDir(fullOptions);
210
209
  var startTime = process.hrtime(); // When using the prebuilt manager, we straight up copy it into the outputDir instead of building it
211
210
 
212
- var manager = prebuiltDir ? (0, _cpy.default)('**', options.outputDir, {
213
- cwd: prebuiltDir,
214
- parents: true
211
+ var manager = prebuiltDir ? _fsExtra.default.copy(prebuiltDir, options.outputDir, {
212
+ dereference: true
215
213
  }).then(function () {}) : managerBuilder.build({
216
214
  startTime: startTime,
217
215
  options: fullOptions
@@ -121,7 +121,7 @@ async function storybookDevServer(options) {
121
121
  var storyIndex = await generator.getIndex();
122
122
  var payload = storyIndex ? {
123
123
  storyIndex: {
124
- storyCount: Object.keys(storyIndex.stories).length,
124
+ storyCount: Object.keys(storyIndex.entries).length,
125
125
  version: storyIndex.v
126
126
  }
127
127
  } : undefined;
@@ -11,10 +11,6 @@ require("core-js/modules/es.promise.js");
11
11
 
12
12
  require("core-js/modules/es.array.sort.js");
13
13
 
14
- require("core-js/modules/es.array.flat.js");
15
-
16
- require("core-js/modules/es.array.unscopables.flat.js");
17
-
18
14
  require("core-js/modules/es.array.flat-map.js");
19
15
 
20
16
  require("core-js/modules/es.array.unscopables.flat-map.js");
@@ -35,13 +31,9 @@ var _nodeLogger = require("@storybook/node-logger");
35
31
 
36
32
  var _csfTools = require("@storybook/csf-tools");
37
33
 
38
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
39
-
40
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
34
+ var _csf = require("@storybook/csf");
41
35
 
42
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
43
-
44
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
36
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
45
37
 
46
38
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
47
39
 
@@ -55,6 +47,16 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
55
47
 
56
48
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
57
49
 
50
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
51
+
52
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
53
+
54
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
55
+
56
+ var makeAbsolute = function (otherImport, normalizedPath, workingDir) {
57
+ return otherImport.startsWith('.') ? (0, _slash.default)(_path.default.resolve(workingDir, (0, _coreCommon.normalizeStoryPath)(_path.default.join(_path.default.dirname(normalizedPath), otherImport)))) : otherImport;
58
+ };
59
+
58
60
  class StoryIndexGenerator {
59
61
  // An internal cache mapping specifiers to a set of path=><set of stories>
60
62
  // Later, we'll combine each of these subsets together to form the full index
@@ -64,9 +66,9 @@ class StoryIndexGenerator {
64
66
  constructor(specifiers, options) {
65
67
  this.specifiers = specifiers;
66
68
  this.options = options;
67
- this.storyIndexEntries = void 0;
69
+ this.specifierToCache = void 0;
68
70
  this.lastIndex = void 0;
69
- this.storyIndexEntries = new Map();
71
+ this.specifierToCache = new Map();
70
72
  }
71
73
 
72
74
  async initialize() {
@@ -91,22 +93,157 @@ class StoryIndexGenerator {
91
93
  pathToSubIndex[absolutePath] = false;
92
94
  });
93
95
 
94
- _this.storyIndexEntries.set(specifier, pathToSubIndex);
96
+ _this.specifierToCache.set(specifier, pathToSubIndex);
95
97
  })); // Extract stories for each file
96
98
 
97
99
  await this.ensureExtracted();
98
100
  }
101
+ /**
102
+ * Run the updater function over all the empty cache entries
103
+ */
99
104
 
100
- async ensureExtracted() {
105
+
106
+ async updateExtracted(updater) {
101
107
  var _this2 = this;
102
108
 
103
- return (await Promise.all(this.specifiers.map(async function (specifier) {
104
- var entry = _this2.storyIndexEntries.get(specifier);
109
+ await Promise.all(this.specifiers.map(async function (specifier) {
110
+ var entry = _this2.specifierToCache.get(specifier);
105
111
 
106
112
  return Promise.all(Object.keys(entry).map(async function (absolutePath) {
107
- return entry[absolutePath] || _this2.extractStories(specifier, absolutePath);
113
+ entry[absolutePath] = entry[absolutePath] || (await updater(specifier, absolutePath));
108
114
  }));
109
- }))).flat();
115
+ }));
116
+ }
117
+
118
+ isDocsMdx(absolutePath) {
119
+ return /(?<!\.stories)\.mdx$/i.test(absolutePath);
120
+ }
121
+
122
+ async ensureExtracted() {
123
+ var _this3 = this;
124
+
125
+ // First process all the story files. Then, in a second pass,
126
+ // process the docs files. The reason for this is that the docs
127
+ // files may use the `<Meta of={XStories} />` syntax, which requires
128
+ // that the story file that contains the meta be processed first.
129
+ await this.updateExtracted(async function (specifier, absolutePath) {
130
+ return _this3.isDocsMdx(absolutePath) ? false : _this3.extractStories(specifier, absolutePath);
131
+ });
132
+ await this.updateExtracted(async function (specifier, absolutePath) {
133
+ return _this3.extractDocs(specifier, absolutePath);
134
+ });
135
+ return this.specifiers.flatMap(function (specifier) {
136
+ var cache = _this3.specifierToCache.get(specifier);
137
+
138
+ return Object.values(cache).flatMap(function (entry) {
139
+ if (!entry) return [];
140
+ if (entry.type === 'docs') return [entry];
141
+ return entry.entries;
142
+ });
143
+ });
144
+ }
145
+
146
+ findDependencies(absoluteImports) {
147
+ var dependencies = [];
148
+ var foundImports = new Set();
149
+ this.specifierToCache.forEach(function (cache) {
150
+ var fileNames = Object.keys(cache).filter(function (fileName) {
151
+ var foundImport = absoluteImports.find(function (storyImport) {
152
+ return fileName.startsWith(storyImport);
153
+ });
154
+ if (foundImport) foundImports.add(foundImport);
155
+ return !!foundImport;
156
+ });
157
+ fileNames.forEach(function (fileName) {
158
+ var cacheEntry = cache[fileName];
159
+
160
+ if (cacheEntry && cacheEntry.type === 'stories') {
161
+ dependencies.push(cacheEntry);
162
+ } else {
163
+ throw new Error(`Unexpected dependency: ${cacheEntry}`);
164
+ }
165
+ });
166
+ }); // imports can include non-story imports, so it's ok if
167
+ // there are fewer foundImports than absoluteImports
168
+ // if (absoluteImports.length !== foundImports.size) {
169
+ // throw new Error(`Missing dependencies: ${absoluteImports.filter((p) => !foundImports.has(p))}`));
170
+ // }
171
+
172
+ return dependencies;
173
+ }
174
+
175
+ async extractDocs(specifier, absolutePath) {
176
+ var _this4 = this;
177
+
178
+ var relativePath = _path.default.relative(this.options.workingDir, absolutePath);
179
+
180
+ try {
181
+ if (!this.options.storyStoreV7) {
182
+ throw new Error(`You cannot use \`.mdx\` files without using \`storyStoreV7\`.`);
183
+ }
184
+
185
+ var normalizedPath = (0, _coreCommon.normalizeStoryPath)(relativePath);
186
+ var importPath = (0, _slash.default)(normalizedPath); // This `await require(...)` is a bit of a hack. It's necessary because
187
+ // `docs-mdx` depends on ESM code, which must be asynchronously imported
188
+ // to be used in CJS. Unfortunately, we cannot use `import()` here, because
189
+ // it will be transpiled down to `require()` by Babel. So instead, we require
190
+ // a CJS export from `@storybook/docs-mdx` that does the `async import` for us.
191
+ // eslint-disable-next-line global-require
192
+
193
+ var _await$require = await require('@storybook/docs-mdx'),
194
+ analyze = _await$require.analyze;
195
+
196
+ var content = await _fsExtra.default.readFile(absolutePath, 'utf8'); // { title?, of?, imports? }
197
+
198
+ var result = analyze(content);
199
+ var absoluteImports = result.imports.map(function (p) {
200
+ return makeAbsolute(p, normalizedPath, _this4.options.workingDir);
201
+ }); // Go through the cache and collect all of the cache entries that this docs file depends on.
202
+ // We'll use this to make sure this docs cache entry is invalidated when any of its dependents
203
+ // are invalidated.
204
+
205
+ var dependencies = this.findDependencies(absoluteImports); // Also, if `result.of` is set, it means that we're using the `<Meta of={XStories} />` syntax,
206
+ // so find the `title` defined the file that `meta` points to.
207
+
208
+ var ofTitle;
209
+
210
+ if (result.of) {
211
+ var absoluteOf = makeAbsolute(result.of, normalizedPath, this.options.workingDir);
212
+ dependencies.forEach(function (dep) {
213
+ if (dep.entries.length > 0) {
214
+ var first = dep.entries[0];
215
+
216
+ if (_path.default.resolve(_this4.options.workingDir, first.importPath).startsWith(absoluteOf)) {
217
+ ofTitle = first.title;
218
+ }
219
+ }
220
+ });
221
+ if (!ofTitle) throw new Error(`Could not find "${result.of}" for docs file "${relativePath}".`);
222
+ } // Track that we depend on this for easy invalidation later.
223
+
224
+
225
+ dependencies.forEach(function (dep) {
226
+ dep.dependents.push(absolutePath);
227
+ });
228
+ var title = (0, _store.userOrAutoTitleFromSpecifier)(importPath, specifier, result.title || ofTitle);
229
+ var name = 'docs';
230
+ var id = (0, _csf.toId)(title, name);
231
+ var docsEntry = {
232
+ id: id,
233
+ title: title,
234
+ name: name,
235
+ importPath: importPath,
236
+ storiesImports: dependencies.map(function (dep) {
237
+ return dep.entries[0].importPath;
238
+ }),
239
+ type: 'docs'
240
+ };
241
+ return docsEntry;
242
+ } catch (err) {
243
+ _nodeLogger.logger.warn(`🚨 Extraction error on ${relativePath}: ${err}`);
244
+
245
+ throw err;
246
+ }
110
247
  }
111
248
 
112
249
  async index(filePath, options) {
@@ -124,8 +261,7 @@ class StoryIndexGenerator {
124
261
  async extractStories(specifier, absolutePath) {
125
262
  var relativePath = _path.default.relative(this.options.workingDir, absolutePath);
126
263
 
127
- var fileStories = {};
128
- var entry = this.storyIndexEntries.get(specifier);
264
+ var entries = [];
129
265
 
130
266
  try {
131
267
  var importPath = (0, _slash.default)((0, _coreCommon.normalizeStoryPath)(relativePath));
@@ -139,14 +275,23 @@ class StoryIndexGenerator {
139
275
  });
140
276
  csf.stories.forEach(function ({
141
277
  id: id,
142
- name: name
278
+ name: name,
279
+ parameters: parameters
143
280
  }) {
144
- fileStories[id] = {
281
+ var base = {
145
282
  id: id,
146
283
  title: csf.meta.title,
147
284
  name: name,
148
285
  importPath: importPath
149
286
  };
287
+ var entry = parameters !== null && parameters !== void 0 && parameters.docsOnly ? _objectSpread(_objectSpread({}, base), {}, {
288
+ type: 'docs',
289
+ storiesImports: [],
290
+ legacy: true
291
+ }) : _objectSpread(_objectSpread({}, base), {}, {
292
+ type: 'story'
293
+ });
294
+ entries.push(entry);
150
295
  });
151
296
  } catch (err) {
152
297
  if (err.name === 'NoMetaError') {
@@ -158,16 +303,19 @@ class StoryIndexGenerator {
158
303
  }
159
304
  }
160
305
 
161
- entry[absolutePath] = fileStories;
162
- return fileStories;
306
+ return {
307
+ entries: entries,
308
+ type: 'stories',
309
+ dependents: []
310
+ };
163
311
  }
164
312
 
165
313
  async sortStories(storiesList) {
166
- var stories = {};
167
- storiesList.forEach(function (subStories) {
168
- Object.assign(stories, subStories);
314
+ var entries = {};
315
+ storiesList.forEach(function (entry) {
316
+ entries[entry.id] = entry;
169
317
  });
170
- var sortableStories = Object.values(stories); // Skip sorting if we're in v6 mode because we don't have
318
+ var sortableStories = Object.values(entries); // Skip sorting if we're in v6 mode because we don't have
171
319
  // all the info we need here
172
320
 
173
321
  if (this.options.storyStoreV7) {
@@ -194,14 +342,15 @@ class StoryIndexGenerator {
194
342
  var titleToStoryCount = Object.values(sorted).reduce(function (acc, story) {
195
343
  acc[story.title] = (acc[story.title] || 0) + 1;
196
344
  return acc;
197
- }, {});
345
+ }, {}); // @ts-ignore
346
+
198
347
  compat = Object.entries(sorted).reduce(function (acc, entry) {
199
348
  var _entry = _slicedToArray(entry, 2),
200
349
  id = _entry[0],
201
350
  story = _entry[1];
202
351
 
352
+ if (story.type === 'docs') return acc;
203
353
  acc[id] = _objectSpread(_objectSpread({}, story), {}, {
204
- id: id,
205
354
  kind: story.title,
206
355
  story: story.name,
207
356
  parameters: {
@@ -215,30 +364,65 @@ class StoryIndexGenerator {
215
364
  }
216
365
 
217
366
  this.lastIndex = {
218
- v: 3,
219
- stories: compat
367
+ v: 4,
368
+ entries: compat
220
369
  };
221
370
  return this.lastIndex;
222
371
  }
223
372
 
224
373
  invalidate(specifier, importPath, removed) {
374
+ var _this5 = this;
375
+
225
376
  var absolutePath = (0, _slash.default)(_path.default.resolve(this.options.workingDir, importPath));
226
- var pathToEntries = this.storyIndexEntries.get(specifier);
377
+ var cache = this.specifierToCache.get(specifier);
378
+ var cacheEntry = cache[absolutePath];
379
+
380
+ if (cacheEntry && cacheEntry.type === 'stories') {
381
+ var dependents = cacheEntry.dependents;
382
+ var invalidated = new Set(); // the dependent can be in ANY cache, so we loop over all of them
383
+
384
+ this.specifierToCache.forEach(function (otherCache) {
385
+ dependents.forEach(function (dep) {
386
+ if (otherCache[dep]) {
387
+ invalidated.add(dep); // eslint-disable-next-line no-param-reassign
388
+
389
+ otherCache[dep] = false;
390
+ }
391
+ });
392
+ });
393
+ var notFound = dependents.filter(function (dep) {
394
+ return !invalidated.has(dep);
395
+ });
396
+
397
+ if (notFound.length > 0) {
398
+ throw new Error(`Could not invalidate ${notFound.length} deps: ${notFound.join(', ')}`);
399
+ }
400
+ }
227
401
 
228
402
  if (removed) {
229
- delete pathToEntries[absolutePath];
403
+ if (cacheEntry && cacheEntry.type === 'docs') {
404
+ var absoluteImports = cacheEntry.storiesImports.map(function (p) {
405
+ return _path.default.resolve(_this5.options.workingDir, p);
406
+ });
407
+ var dependencies = this.findDependencies(absoluteImports);
408
+ dependencies.forEach(function (dep) {
409
+ return dep.dependents.splice(dep.dependents.indexOf(absolutePath), 1);
410
+ });
411
+ }
412
+
413
+ delete cache[absolutePath];
230
414
  } else {
231
- pathToEntries[absolutePath] = false;
415
+ cache[absolutePath] = false;
232
416
  }
233
417
 
234
418
  this.lastIndex = null;
235
419
  }
236
420
 
237
421
  async getStorySortParameter() {
238
- var _this3 = this;
422
+ var _this6 = this;
239
423
 
240
424
  var previewFile = ['js', 'jsx', 'ts', 'tsx'].map(function (ext) {
241
- return _path.default.join(_this3.options.configDir, `preview.${ext}`);
425
+ return _path.default.join(_this6.options.configDir, `preview.${ext}`);
242
426
  }).find(function (fname) {
243
427
  return _fsExtra.default.existsSync(fname);
244
428
  });
@@ -254,7 +438,7 @@ class StoryIndexGenerator {
254
438
 
255
439
 
256
440
  storyFileNames() {
257
- return Array.from(this.storyIndexEntries.values()).flatMap(function (r) {
441
+ return Array.from(this.specifierToCache.values()).flatMap(function (r) {
258
442
  return Object.keys(r);
259
443
  });
260
444
  }
@@ -19,7 +19,9 @@ var _tsDedent = _interopRequireDefault(require("ts-dedent"));
19
19
 
20
20
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
21
 
22
+ // @ts-ignore
22
23
  // betterOpn alias used because also loading open
24
+ // @ts-ignore
23
25
  function openInBrowser(address) {
24
26
  (0, _xDefaultBrowser.default)(async function (err, res) {
25
27
  try {
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.DEBOUNCE = void 0;
6
+ exports.convertToIndexV3 = exports.DEBOUNCE = void 0;
7
7
  exports.extractStoriesJson = extractStoriesJson;
8
8
  exports.useStoriesJson = useStoriesJson;
9
9
 
@@ -11,21 +11,33 @@ require("core-js/modules/es.promise.js");
11
11
 
12
12
  var _fsExtra = _interopRequireDefault(require("fs-extra"));
13
13
 
14
- var _lodash = require("lodash");
14
+ var _debounce = _interopRequireDefault(require("lodash/debounce"));
15
15
 
16
16
  var _coreEvents = require("@storybook/core-events");
17
17
 
18
18
  var _watchStorySpecifiers = require("./watch-story-specifiers");
19
19
 
20
+ var _excluded = ["type"];
21
+
20
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
23
 
24
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
25
+
26
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
27
+
28
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
29
+
30
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
31
+
32
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
33
+
22
34
  var DEBOUNCE = 100;
23
35
  exports.DEBOUNCE = DEBOUNCE;
24
36
 
25
- async function extractStoriesJson(outputFile, initializedStoryIndexGenerator) {
37
+ async function extractStoriesJson(outputFile, initializedStoryIndexGenerator, transform) {
26
38
  var generator = await initializedStoryIndexGenerator;
27
39
  var storyIndex = await generator.getIndex();
28
- await _fsExtra.default.writeJson(outputFile, storyIndex);
40
+ await _fsExtra.default.writeJson(outputFile, transform ? transform(storyIndex) : storyIndex);
29
41
  }
30
42
 
31
43
  function useStoriesJson({
@@ -35,7 +47,7 @@ function useStoriesJson({
35
47
  serverChannel: serverChannel,
36
48
  normalizedStories: normalizedStories
37
49
  }) {
38
- var maybeInvalidate = (0, _lodash.debounce)(function () {
50
+ var maybeInvalidate = (0, _debounce.default)(function () {
39
51
  return serverChannel.emit(_coreEvents.STORY_INDEX_INVALIDATED);
40
52
  }, DEBOUNCE, {
41
53
  leading: true
@@ -47,15 +59,55 @@ function useStoriesJson({
47
59
  generator.invalidate(specifier, path, removed);
48
60
  maybeInvalidate();
49
61
  });
62
+ router.use('/index.json', async function (req, res) {
63
+ try {
64
+ var generator = await initializedStoryIndexGenerator;
65
+
66
+ var _index = await generator.getIndex();
67
+
68
+ res.header('Content-Type', 'application/json');
69
+ res.send(JSON.stringify(_index));
70
+ } catch (err) {
71
+ res.status(500);
72
+ res.send(err.message);
73
+ }
74
+ });
50
75
  router.use('/stories.json', async function (req, res) {
51
76
  try {
52
77
  var generator = await initializedStoryIndexGenerator;
53
- var index = await generator.getIndex();
78
+
79
+ var _index2 = convertToIndexV3(await generator.getIndex());
80
+
54
81
  res.header('Content-Type', 'application/json');
55
- res.send(JSON.stringify(index));
82
+ res.send(JSON.stringify(_index2));
56
83
  } catch (err) {
57
84
  res.status(500);
58
85
  res.send(err.message);
59
86
  }
60
87
  });
61
- }
88
+ }
89
+
90
+ var convertToIndexV3 = function (index) {
91
+ var entries = index.entries;
92
+ var stories = Object.entries(entries).reduce(function (acc, [id, entry]) {
93
+ var type = entry.type,
94
+ rest = _objectWithoutProperties(entry, _excluded);
95
+
96
+ acc[id] = _objectSpread(_objectSpread({}, rest), {}, {
97
+ kind: rest.title,
98
+ story: rest.name,
99
+ parameters: {
100
+ __id: rest.id,
101
+ docsOnly: type === 'docs',
102
+ fileName: rest.importPath
103
+ }
104
+ });
105
+ return acc;
106
+ }, {});
107
+ return {
108
+ v: 3,
109
+ stories: stories
110
+ };
111
+ };
112
+
113
+ exports.convertToIndexV3 = convertToIndexV3;
@@ -17,8 +17,11 @@ var _path = _interopRequireDefault(require("path"));
17
17
 
18
18
  var _globby = _interopRequireDefault(require("globby"));
19
19
 
20
+ var _uniq = _interopRequireDefault(require("lodash/uniq"));
21
+
20
22
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
23
 
24
+ // @ts-ignore
22
25
  var isDirectory = function (directory) {
23
26
  try {
24
27
  return _fs.default.lstatSync(directory).isDirectory();
@@ -43,9 +46,9 @@ function watchStorySpecifiers(specifiers, options, onInvalidate) {
43
46
  ignored: ['**/.git', 'node_modules']
44
47
  });
45
48
  wp.watch({
46
- directories: specifiers.map(function (ns) {
49
+ directories: (0, _uniq.default)(specifiers.map(function (ns) {
47
50
  return ns.directory;
48
- })
51
+ }))
49
52
  });
50
53
 
51
54
  async function onChangeOrRemove(watchpackPath, removed) {
@@ -19,7 +19,6 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
19
19
  import "core-js/modules/es.promise.js";
20
20
  import "core-js/modules/es.symbol.description.js";
21
21
  import chalk from 'chalk';
22
- import cpy from 'cpy';
23
22
  import fs from 'fs-extra';
24
23
  import path, { join } from 'path';
25
24
  import dedent from 'ts-dedent';
@@ -30,7 +29,7 @@ import { loadAllPresets, normalizeStories, logConfig, loadMainConfig } from '@st
30
29
  import { outputStats } from './utils/output-stats';
31
30
  import { copyAllStaticFiles, copyAllStaticFilesRelativeToMain } from './utils/copy-all-static-files';
32
31
  import { getBuilders } from './utils/get-builders';
33
- import { extractStoriesJson } from './utils/stories-json';
32
+ import { extractStoriesJson, convertToIndexV3 } from './utils/stories-json';
34
33
  import { extractStorybookMetadata } from './utils/metadata';
35
34
  import { StoryIndexGenerator } from './utils/StoryIndexGenerator';
36
35
  export async function buildStaticStandalone(options) {
@@ -60,7 +59,7 @@ export async function buildStaticStandalone(options) {
60
59
  }
61
60
 
62
61
  await fs.emptyDir(options.outputDir);
63
- await cpy(defaultFavIcon, options.outputDir);
62
+ await fs.copyFile(defaultFavIcon, path.join(options.outputDir, path.basename(defaultFavIcon)));
64
63
 
65
64
  var _await$import = await import('@storybook/manager-webpack5/prebuilt-manager'),
66
65
  getPrebuiltDir = _await$import.getPrebuiltDir;
@@ -135,7 +134,8 @@ export async function buildStaticStandalone(options) {
135
134
  initializedStoryIndexGenerator = generator.initialize().then(function () {
136
135
  return generator;
137
136
  });
138
- extractTasks.push(extractStoriesJson(path.join(options.outputDir, 'stories.json'), initializedStoryIndexGenerator));
137
+ extractTasks.push(extractStoriesJson(path.join(options.outputDir, 'stories.json'), initializedStoryIndexGenerator, convertToIndexV3));
138
+ extractTasks.push(extractStoriesJson(path.join(options.outputDir, 'index.json'), initializedStoryIndexGenerator));
139
139
  }
140
140
 
141
141
  var core = await presets.apply('core');
@@ -149,7 +149,7 @@ export async function buildStaticStandalone(options) {
149
149
  var storyIndex = await generator.getIndex();
150
150
  var payload = storyIndex ? {
151
151
  storyIndex: {
152
- storyCount: Object.keys(storyIndex.stories).length,
152
+ storyCount: Object.keys(storyIndex.entries).length,
153
153
  version: storyIndex.v
154
154
  }
155
155
  } : undefined;
@@ -176,9 +176,8 @@ export async function buildStaticStandalone(options) {
176
176
  var prebuiltDir = await getPrebuiltDir(fullOptions);
177
177
  var startTime = process.hrtime(); // When using the prebuilt manager, we straight up copy it into the outputDir instead of building it
178
178
 
179
- var manager = prebuiltDir ? cpy('**', options.outputDir, {
180
- cwd: prebuiltDir,
181
- parents: true
179
+ var manager = prebuiltDir ? fs.copy(prebuiltDir, options.outputDir, {
180
+ dereference: true
182
181
  }).then(function () {}) : managerBuilder.build({
183
182
  startTime: startTime,
184
183
  options: fullOptions
@@ -88,7 +88,7 @@ export async function storybookDevServer(options) {
88
88
  var storyIndex = await generator.getIndex();
89
89
  var payload = storyIndex ? {
90
90
  storyIndex: {
91
- storyCount: Object.keys(storyIndex.stories).length,
91
+ storyCount: Object.keys(storyIndex.entries).length,
92
92
  version: storyIndex.v
93
93
  }
94
94
  } : undefined;
package/dist/esm/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ // eslint-disable-next-line @typescript-eslint/triple-slash-reference
2
+ /// <reference path="./typings.d.ts" />
1
3
  import { getPreviewHeadTemplate, getManagerHeadTemplate, getManagerMainTemplate, getPreviewBodyTemplate, getPreviewMainTemplate } from '@storybook/core-common';
2
4
  export { getPreviewHeadTemplate, getManagerHeadTemplate, getManagerMainTemplate, getPreviewBodyTemplate, getPreviewMainTemplate };
3
5
  export * from './build-static';
@@ -1,9 +1,3 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
2
-
3
- function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
-
5
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
-
7
1
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
8
2
 
9
3
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
@@ -16,10 +10,14 @@ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Sy
16
10
 
17
11
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
18
12
 
13
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
14
+
15
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
16
+
17
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
18
+
19
19
  import "core-js/modules/es.promise.js";
20
20
  import "core-js/modules/es.array.sort.js";
21
- import "core-js/modules/es.array.flat.js";
22
- import "core-js/modules/es.array.unscopables.flat.js";
23
21
  import "core-js/modules/es.array.flat-map.js";
24
22
  import "core-js/modules/es.array.unscopables.flat-map.js";
25
23
  import "core-js/modules/es.symbol.description.js";
@@ -31,6 +29,12 @@ import { userOrAutoTitleFromSpecifier, sortStoriesV7 } from '@storybook/store';
31
29
  import { normalizeStoryPath } from '@storybook/core-common';
32
30
  import { logger } from '@storybook/node-logger';
33
31
  import { getStorySortParameter } from '@storybook/csf-tools';
32
+ import { toId } from '@storybook/csf';
33
+
34
+ var makeAbsolute = function (otherImport, normalizedPath, workingDir) {
35
+ return otherImport.startsWith('.') ? slash(path.resolve(workingDir, normalizeStoryPath(path.join(path.dirname(normalizedPath), otherImport)))) : otherImport;
36
+ };
37
+
34
38
  export class StoryIndexGenerator {
35
39
  // An internal cache mapping specifiers to a set of path=><set of stories>
36
40
  // Later, we'll combine each of these subsets together to form the full index
@@ -40,9 +44,9 @@ export class StoryIndexGenerator {
40
44
  constructor(specifiers, options) {
41
45
  this.specifiers = specifiers;
42
46
  this.options = options;
43
- this.storyIndexEntries = void 0;
47
+ this.specifierToCache = void 0;
44
48
  this.lastIndex = void 0;
45
- this.storyIndexEntries = new Map();
49
+ this.specifierToCache = new Map();
46
50
  }
47
51
 
48
52
  async initialize() {
@@ -65,22 +69,156 @@ export class StoryIndexGenerator {
65
69
  pathToSubIndex[absolutePath] = false;
66
70
  });
67
71
 
68
- _this.storyIndexEntries.set(specifier, pathToSubIndex);
72
+ _this.specifierToCache.set(specifier, pathToSubIndex);
69
73
  })); // Extract stories for each file
70
74
 
71
75
  await this.ensureExtracted();
72
76
  }
77
+ /**
78
+ * Run the updater function over all the empty cache entries
79
+ */
73
80
 
74
- async ensureExtracted() {
81
+
82
+ async updateExtracted(updater) {
75
83
  var _this2 = this;
76
84
 
77
- return (await Promise.all(this.specifiers.map(async function (specifier) {
78
- var entry = _this2.storyIndexEntries.get(specifier);
85
+ await Promise.all(this.specifiers.map(async function (specifier) {
86
+ var entry = _this2.specifierToCache.get(specifier);
79
87
 
80
88
  return Promise.all(Object.keys(entry).map(async function (absolutePath) {
81
- return entry[absolutePath] || _this2.extractStories(specifier, absolutePath);
89
+ entry[absolutePath] = entry[absolutePath] || (await updater(specifier, absolutePath));
82
90
  }));
83
- }))).flat();
91
+ }));
92
+ }
93
+
94
+ isDocsMdx(absolutePath) {
95
+ return /(?<!\.stories)\.mdx$/i.test(absolutePath);
96
+ }
97
+
98
+ async ensureExtracted() {
99
+ var _this3 = this;
100
+
101
+ // First process all the story files. Then, in a second pass,
102
+ // process the docs files. The reason for this is that the docs
103
+ // files may use the `<Meta of={XStories} />` syntax, which requires
104
+ // that the story file that contains the meta be processed first.
105
+ await this.updateExtracted(async function (specifier, absolutePath) {
106
+ return _this3.isDocsMdx(absolutePath) ? false : _this3.extractStories(specifier, absolutePath);
107
+ });
108
+ await this.updateExtracted(async function (specifier, absolutePath) {
109
+ return _this3.extractDocs(specifier, absolutePath);
110
+ });
111
+ return this.specifiers.flatMap(function (specifier) {
112
+ var cache = _this3.specifierToCache.get(specifier);
113
+
114
+ return Object.values(cache).flatMap(function (entry) {
115
+ if (!entry) return [];
116
+ if (entry.type === 'docs') return [entry];
117
+ return entry.entries;
118
+ });
119
+ });
120
+ }
121
+
122
+ findDependencies(absoluteImports) {
123
+ var dependencies = [];
124
+ var foundImports = new Set();
125
+ this.specifierToCache.forEach(function (cache) {
126
+ var fileNames = Object.keys(cache).filter(function (fileName) {
127
+ var foundImport = absoluteImports.find(function (storyImport) {
128
+ return fileName.startsWith(storyImport);
129
+ });
130
+ if (foundImport) foundImports.add(foundImport);
131
+ return !!foundImport;
132
+ });
133
+ fileNames.forEach(function (fileName) {
134
+ var cacheEntry = cache[fileName];
135
+
136
+ if (cacheEntry && cacheEntry.type === 'stories') {
137
+ dependencies.push(cacheEntry);
138
+ } else {
139
+ throw new Error(`Unexpected dependency: ${cacheEntry}`);
140
+ }
141
+ });
142
+ }); // imports can include non-story imports, so it's ok if
143
+ // there are fewer foundImports than absoluteImports
144
+ // if (absoluteImports.length !== foundImports.size) {
145
+ // throw new Error(`Missing dependencies: ${absoluteImports.filter((p) => !foundImports.has(p))}`));
146
+ // }
147
+
148
+ return dependencies;
149
+ }
150
+
151
+ async extractDocs(specifier, absolutePath) {
152
+ var _this4 = this;
153
+
154
+ var relativePath = path.relative(this.options.workingDir, absolutePath);
155
+
156
+ try {
157
+ if (!this.options.storyStoreV7) {
158
+ throw new Error(`You cannot use \`.mdx\` files without using \`storyStoreV7\`.`);
159
+ }
160
+
161
+ var normalizedPath = normalizeStoryPath(relativePath);
162
+ var importPath = slash(normalizedPath); // This `await require(...)` is a bit of a hack. It's necessary because
163
+ // `docs-mdx` depends on ESM code, which must be asynchronously imported
164
+ // to be used in CJS. Unfortunately, we cannot use `import()` here, because
165
+ // it will be transpiled down to `require()` by Babel. So instead, we require
166
+ // a CJS export from `@storybook/docs-mdx` that does the `async import` for us.
167
+ // eslint-disable-next-line global-require
168
+
169
+ var _await$require = await require('@storybook/docs-mdx'),
170
+ analyze = _await$require.analyze;
171
+
172
+ var content = await fs.readFile(absolutePath, 'utf8'); // { title?, of?, imports? }
173
+
174
+ var result = analyze(content);
175
+ var absoluteImports = result.imports.map(function (p) {
176
+ return makeAbsolute(p, normalizedPath, _this4.options.workingDir);
177
+ }); // Go through the cache and collect all of the cache entries that this docs file depends on.
178
+ // We'll use this to make sure this docs cache entry is invalidated when any of its dependents
179
+ // are invalidated.
180
+
181
+ var dependencies = this.findDependencies(absoluteImports); // Also, if `result.of` is set, it means that we're using the `<Meta of={XStories} />` syntax,
182
+ // so find the `title` defined the file that `meta` points to.
183
+
184
+ var ofTitle;
185
+
186
+ if (result.of) {
187
+ var absoluteOf = makeAbsolute(result.of, normalizedPath, this.options.workingDir);
188
+ dependencies.forEach(function (dep) {
189
+ if (dep.entries.length > 0) {
190
+ var first = dep.entries[0];
191
+
192
+ if (path.resolve(_this4.options.workingDir, first.importPath).startsWith(absoluteOf)) {
193
+ ofTitle = first.title;
194
+ }
195
+ }
196
+ });
197
+ if (!ofTitle) throw new Error(`Could not find "${result.of}" for docs file "${relativePath}".`);
198
+ } // Track that we depend on this for easy invalidation later.
199
+
200
+
201
+ dependencies.forEach(function (dep) {
202
+ dep.dependents.push(absolutePath);
203
+ });
204
+ var title = userOrAutoTitleFromSpecifier(importPath, specifier, result.title || ofTitle);
205
+ var name = 'docs';
206
+ var id = toId(title, name);
207
+ var docsEntry = {
208
+ id: id,
209
+ title: title,
210
+ name: name,
211
+ importPath: importPath,
212
+ storiesImports: dependencies.map(function (dep) {
213
+ return dep.entries[0].importPath;
214
+ }),
215
+ type: 'docs'
216
+ };
217
+ return docsEntry;
218
+ } catch (err) {
219
+ logger.warn(`🚨 Extraction error on ${relativePath}: ${err}`);
220
+ throw err;
221
+ }
84
222
  }
85
223
 
86
224
  async index(filePath, options) {
@@ -97,8 +235,7 @@ export class StoryIndexGenerator {
97
235
 
98
236
  async extractStories(specifier, absolutePath) {
99
237
  var relativePath = path.relative(this.options.workingDir, absolutePath);
100
- var fileStories = {};
101
- var entry = this.storyIndexEntries.get(specifier);
238
+ var entries = [];
102
239
 
103
240
  try {
104
241
  var importPath = slash(normalizeStoryPath(relativePath));
@@ -112,14 +249,23 @@ export class StoryIndexGenerator {
112
249
  });
113
250
  csf.stories.forEach(function ({
114
251
  id: id,
115
- name: name
252
+ name: name,
253
+ parameters: parameters
116
254
  }) {
117
- fileStories[id] = {
255
+ var base = {
118
256
  id: id,
119
257
  title: csf.meta.title,
120
258
  name: name,
121
259
  importPath: importPath
122
260
  };
261
+ var entry = parameters !== null && parameters !== void 0 && parameters.docsOnly ? _objectSpread(_objectSpread({}, base), {}, {
262
+ type: 'docs',
263
+ storiesImports: [],
264
+ legacy: true
265
+ }) : _objectSpread(_objectSpread({}, base), {}, {
266
+ type: 'story'
267
+ });
268
+ entries.push(entry);
123
269
  });
124
270
  } catch (err) {
125
271
  if (err.name === 'NoMetaError') {
@@ -130,16 +276,19 @@ export class StoryIndexGenerator {
130
276
  }
131
277
  }
132
278
 
133
- entry[absolutePath] = fileStories;
134
- return fileStories;
279
+ return {
280
+ entries: entries,
281
+ type: 'stories',
282
+ dependents: []
283
+ };
135
284
  }
136
285
 
137
286
  async sortStories(storiesList) {
138
- var stories = {};
139
- storiesList.forEach(function (subStories) {
140
- Object.assign(stories, subStories);
287
+ var entries = {};
288
+ storiesList.forEach(function (entry) {
289
+ entries[entry.id] = entry;
141
290
  });
142
- var sortableStories = Object.values(stories); // Skip sorting if we're in v6 mode because we don't have
291
+ var sortableStories = Object.values(entries); // Skip sorting if we're in v6 mode because we don't have
143
292
  // all the info we need here
144
293
 
145
294
  if (this.options.storyStoreV7) {
@@ -166,14 +315,15 @@ export class StoryIndexGenerator {
166
315
  var titleToStoryCount = Object.values(sorted).reduce(function (acc, story) {
167
316
  acc[story.title] = (acc[story.title] || 0) + 1;
168
317
  return acc;
169
- }, {});
318
+ }, {}); // @ts-ignore
319
+
170
320
  compat = Object.entries(sorted).reduce(function (acc, entry) {
171
321
  var _entry = _slicedToArray(entry, 2),
172
322
  id = _entry[0],
173
323
  story = _entry[1];
174
324
 
325
+ if (story.type === 'docs') return acc;
175
326
  acc[id] = _objectSpread(_objectSpread({}, story), {}, {
176
- id: id,
177
327
  kind: story.title,
178
328
  story: story.name,
179
329
  parameters: {
@@ -187,30 +337,65 @@ export class StoryIndexGenerator {
187
337
  }
188
338
 
189
339
  this.lastIndex = {
190
- v: 3,
191
- stories: compat
340
+ v: 4,
341
+ entries: compat
192
342
  };
193
343
  return this.lastIndex;
194
344
  }
195
345
 
196
346
  invalidate(specifier, importPath, removed) {
347
+ var _this5 = this;
348
+
197
349
  var absolutePath = slash(path.resolve(this.options.workingDir, importPath));
198
- var pathToEntries = this.storyIndexEntries.get(specifier);
350
+ var cache = this.specifierToCache.get(specifier);
351
+ var cacheEntry = cache[absolutePath];
352
+
353
+ if (cacheEntry && cacheEntry.type === 'stories') {
354
+ var dependents = cacheEntry.dependents;
355
+ var invalidated = new Set(); // the dependent can be in ANY cache, so we loop over all of them
356
+
357
+ this.specifierToCache.forEach(function (otherCache) {
358
+ dependents.forEach(function (dep) {
359
+ if (otherCache[dep]) {
360
+ invalidated.add(dep); // eslint-disable-next-line no-param-reassign
361
+
362
+ otherCache[dep] = false;
363
+ }
364
+ });
365
+ });
366
+ var notFound = dependents.filter(function (dep) {
367
+ return !invalidated.has(dep);
368
+ });
369
+
370
+ if (notFound.length > 0) {
371
+ throw new Error(`Could not invalidate ${notFound.length} deps: ${notFound.join(', ')}`);
372
+ }
373
+ }
199
374
 
200
375
  if (removed) {
201
- delete pathToEntries[absolutePath];
376
+ if (cacheEntry && cacheEntry.type === 'docs') {
377
+ var absoluteImports = cacheEntry.storiesImports.map(function (p) {
378
+ return path.resolve(_this5.options.workingDir, p);
379
+ });
380
+ var dependencies = this.findDependencies(absoluteImports);
381
+ dependencies.forEach(function (dep) {
382
+ return dep.dependents.splice(dep.dependents.indexOf(absolutePath), 1);
383
+ });
384
+ }
385
+
386
+ delete cache[absolutePath];
202
387
  } else {
203
- pathToEntries[absolutePath] = false;
388
+ cache[absolutePath] = false;
204
389
  }
205
390
 
206
391
  this.lastIndex = null;
207
392
  }
208
393
 
209
394
  async getStorySortParameter() {
210
- var _this3 = this;
395
+ var _this6 = this;
211
396
 
212
397
  var previewFile = ['js', 'jsx', 'ts', 'tsx'].map(function (ext) {
213
- return path.join(_this3.options.configDir, `preview.${ext}`);
398
+ return path.join(_this6.options.configDir, `preview.${ext}`);
214
399
  }).find(function (fname) {
215
400
  return fs.existsSync(fname);
216
401
  });
@@ -226,7 +411,7 @@ export class StoryIndexGenerator {
226
411
 
227
412
 
228
413
  storyFileNames() {
229
- return Array.from(this.storyIndexEntries.values()).flatMap(function (r) {
414
+ return Array.from(this.specifierToCache.values()).flatMap(function (r) {
230
415
  return Object.keys(r);
231
416
  });
232
417
  }
@@ -1,8 +1,10 @@
1
1
  import "core-js/modules/es.promise.js";
2
- import { logger } from '@storybook/node-logger';
2
+ import { logger } from '@storybook/node-logger'; // @ts-ignore
3
+
3
4
  import betterOpn from 'better-opn'; // betterOpn alias used because also loading open
4
5
 
5
- import open from 'open';
6
+ import open from 'open'; // @ts-ignore
7
+
6
8
  import getDefaultBrowser from 'x-default-browser';
7
9
  import dedent from 'ts-dedent';
8
10
  export function openInBrowser(address) {
@@ -1,13 +1,25 @@
1
+ var _excluded = ["type"];
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
4
+
5
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
6
+
7
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
8
+
9
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
10
+
11
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
12
+
1
13
  import "core-js/modules/es.promise.js";
2
14
  import fs from 'fs-extra';
3
- import { debounce } from 'lodash';
15
+ import debounce from 'lodash/debounce';
4
16
  import { STORY_INDEX_INVALIDATED } from '@storybook/core-events';
5
17
  import { watchStorySpecifiers } from './watch-story-specifiers';
6
18
  export var DEBOUNCE = 100;
7
- export async function extractStoriesJson(outputFile, initializedStoryIndexGenerator) {
19
+ export async function extractStoriesJson(outputFile, initializedStoryIndexGenerator, transform) {
8
20
  var generator = await initializedStoryIndexGenerator;
9
21
  var storyIndex = await generator.getIndex();
10
- await fs.writeJson(outputFile, storyIndex);
22
+ await fs.writeJson(outputFile, transform ? transform(storyIndex) : storyIndex);
11
23
  }
12
24
  export function useStoriesJson({
13
25
  router: router,
@@ -28,15 +40,52 @@ export function useStoriesJson({
28
40
  generator.invalidate(specifier, path, removed);
29
41
  maybeInvalidate();
30
42
  });
43
+ router.use('/index.json', async function (req, res) {
44
+ try {
45
+ var generator = await initializedStoryIndexGenerator;
46
+
47
+ var _index = await generator.getIndex();
48
+
49
+ res.header('Content-Type', 'application/json');
50
+ res.send(JSON.stringify(_index));
51
+ } catch (err) {
52
+ res.status(500);
53
+ res.send(err.message);
54
+ }
55
+ });
31
56
  router.use('/stories.json', async function (req, res) {
32
57
  try {
33
58
  var generator = await initializedStoryIndexGenerator;
34
- var index = await generator.getIndex();
59
+
60
+ var _index2 = convertToIndexV3(await generator.getIndex());
61
+
35
62
  res.header('Content-Type', 'application/json');
36
- res.send(JSON.stringify(index));
63
+ res.send(JSON.stringify(_index2));
37
64
  } catch (err) {
38
65
  res.status(500);
39
66
  res.send(err.message);
40
67
  }
41
68
  });
42
- }
69
+ }
70
+ export var convertToIndexV3 = function (index) {
71
+ var entries = index.entries;
72
+ var stories = Object.entries(entries).reduce(function (acc, [id, entry]) {
73
+ var type = entry.type,
74
+ rest = _objectWithoutProperties(entry, _excluded);
75
+
76
+ acc[id] = _objectSpread(_objectSpread({}, rest), {}, {
77
+ kind: rest.title,
78
+ story: rest.name,
79
+ parameters: {
80
+ __id: rest.id,
81
+ docsOnly: type === 'docs',
82
+ fileName: rest.importPath
83
+ }
84
+ });
85
+ return acc;
86
+ }, {});
87
+ return {
88
+ v: 3,
89
+ stories: stories
90
+ };
91
+ };
@@ -1,9 +1,11 @@
1
1
  import "core-js/modules/es.promise.js";
2
+ // @ts-ignore
2
3
  import Watchpack from 'watchpack';
3
4
  import slash from 'slash';
4
5
  import fs from 'fs';
5
6
  import path from 'path';
6
7
  import glob from 'globby';
8
+ import uniq from 'lodash/uniq';
7
9
 
8
10
  var isDirectory = function (directory) {
9
11
  try {
@@ -29,9 +31,9 @@ export function watchStorySpecifiers(specifiers, options, onInvalidate) {
29
31
  ignored: ['**/.git', 'node_modules']
30
32
  });
31
33
  wp.watch({
32
- directories: specifiers.map(function (ns) {
34
+ directories: uniq(specifiers.map(function (ns) {
33
35
  return ns.directory;
34
- })
36
+ }))
35
37
  });
36
38
 
37
39
  async function onChangeOrRemove(watchpackPath, removed) {
@@ -1,3 +1,4 @@
1
+ /// <reference path="../../src/typings.d.ts" />
1
2
  import { getPreviewHeadTemplate, getManagerHeadTemplate, getManagerMainTemplate, getPreviewBodyTemplate, getPreviewMainTemplate } from '@storybook/core-common';
2
3
  export { getPreviewHeadTemplate, getManagerHeadTemplate, getManagerMainTemplate, getPreviewBodyTemplate, getPreviewMainTemplate, };
3
4
  export * from './build-static';
@@ -1,5 +1,12 @@
1
- import type { Path, StoryIndex } from '@storybook/store';
1
+ import type { Path, StoryIndex, IndexEntry, DocsIndexEntry } from '@storybook/store';
2
2
  import type { StoryIndexer, IndexerOptions, NormalizedStoriesSpecifier } from '@storybook/core-common';
3
+ declare type DocsCacheEntry = DocsIndexEntry;
4
+ declare type StoriesCacheEntry = {
5
+ entries: IndexEntry[];
6
+ dependents: Path[];
7
+ type: 'stories';
8
+ };
9
+ declare type CacheEntry = false | StoriesCacheEntry | DocsCacheEntry;
3
10
  export declare class StoryIndexGenerator {
4
11
  readonly specifiers: NormalizedStoriesSpecifier[];
5
12
  readonly options: {
@@ -9,7 +16,7 @@ export declare class StoryIndexGenerator {
9
16
  storyStoreV7: boolean;
10
17
  storyIndexers: StoryIndexer[];
11
18
  };
12
- private storyIndexEntries;
19
+ private specifierToCache;
13
20
  private lastIndex?;
14
21
  constructor(specifiers: NormalizedStoriesSpecifier[], options: {
15
22
  workingDir: Path;
@@ -19,12 +26,20 @@ export declare class StoryIndexGenerator {
19
26
  storyIndexers: StoryIndexer[];
20
27
  });
21
28
  initialize(): Promise<void>;
22
- ensureExtracted(): Promise<StoryIndex['stories'][]>;
29
+ /**
30
+ * Run the updater function over all the empty cache entries
31
+ */
32
+ updateExtracted(updater: (specifier: NormalizedStoriesSpecifier, absolutePath: Path) => Promise<CacheEntry>): Promise<void>;
33
+ isDocsMdx(absolutePath: Path): boolean;
34
+ ensureExtracted(): Promise<IndexEntry[]>;
35
+ findDependencies(absoluteImports: Path[]): StoriesCacheEntry[];
36
+ extractDocs(specifier: NormalizedStoriesSpecifier, absolutePath: Path): Promise<DocsIndexEntry>;
23
37
  index(filePath: string, options: IndexerOptions): Promise<import("@storybook/core-common").StoryIndex>;
24
- extractStories(specifier: NormalizedStoriesSpecifier, absolutePath: Path): Promise<Record<string, import("@storybook/store").StoryIndexEntry>>;
25
- sortStories(storiesList: StoryIndex['stories'][]): Promise<Record<string, import("@storybook/store").StoryIndexEntry>>;
38
+ extractStories(specifier: NormalizedStoriesSpecifier, absolutePath: Path): Promise<StoriesCacheEntry>;
39
+ sortStories(storiesList: IndexEntry[]): Promise<Record<string, IndexEntry>>;
26
40
  getIndex(): Promise<StoryIndex>;
27
41
  invalidate(specifier: NormalizedStoriesSpecifier, importPath: Path, removed: boolean): void;
28
42
  getStorySortParameter(): Promise<any>;
29
43
  storyFileNames(): string[];
30
44
  }
45
+ export {};
@@ -1,9 +1,10 @@
1
1
  import { Router } from 'express';
2
2
  import type { NormalizedStoriesSpecifier } from '@storybook/core-common';
3
+ import type { StoryIndex, StoryIndexV3 } from '@storybook/store';
3
4
  import { StoryIndexGenerator } from './StoryIndexGenerator';
4
5
  import { ServerChannel } from './get-server-channel';
5
6
  export declare const DEBOUNCE = 100;
6
- export declare function extractStoriesJson(outputFile: string, initializedStoryIndexGenerator: Promise<StoryIndexGenerator>): Promise<void>;
7
+ export declare function extractStoriesJson(outputFile: string, initializedStoryIndexGenerator: Promise<StoryIndexGenerator>, transform?: (index: StoryIndex) => any): Promise<void>;
7
8
  export declare function useStoriesJson({ router, initializedStoryIndexGenerator, workingDir, serverChannel, normalizedStories, }: {
8
9
  router: Router;
9
10
  initializedStoryIndexGenerator: Promise<StoryIndexGenerator>;
@@ -11,3 +12,4 @@ export declare function useStoriesJson({ router, initializedStoryIndexGenerator,
11
12
  workingDir?: string;
12
13
  normalizedStories: NormalizedStoriesSpecifier[];
13
14
  }): void;
15
+ export declare const convertToIndexV3: (index: StoryIndex) => StoryIndexV3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/core-server",
3
- "version": "7.0.0-alpha.4",
3
+ "version": "7.0.0-alpha.7",
4
4
  "description": "Storybook framework-agnostic API",
5
5
  "keywords": [
6
6
  "storybook"
@@ -33,16 +33,17 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@discoveryjs/json-ext": "^0.5.3",
36
- "@storybook/core-client": "7.0.0-alpha.4",
37
- "@storybook/core-common": "7.0.0-alpha.4",
38
- "@storybook/core-events": "7.0.0-alpha.4",
36
+ "@storybook/core-client": "7.0.0-alpha.7",
37
+ "@storybook/core-common": "7.0.0-alpha.7",
38
+ "@storybook/core-events": "7.0.0-alpha.7",
39
39
  "@storybook/csf": "0.0.2--canary.4566f4d.1",
40
- "@storybook/csf-tools": "7.0.0-alpha.4",
41
- "@storybook/manager-webpack5": "7.0.0-alpha.4",
42
- "@storybook/node-logger": "7.0.0-alpha.4",
40
+ "@storybook/csf-tools": "7.0.0-alpha.7",
41
+ "@storybook/docs-mdx": "0.0.1-canary.1.4bea5cc.0",
42
+ "@storybook/manager-webpack5": "7.0.0-alpha.7",
43
+ "@storybook/node-logger": "7.0.0-alpha.7",
43
44
  "@storybook/semver": "^7.3.2",
44
- "@storybook/store": "7.0.0-alpha.4",
45
- "@storybook/telemetry": "7.0.0-alpha.4",
45
+ "@storybook/store": "7.0.0-alpha.7",
46
+ "@storybook/telemetry": "7.0.0-alpha.7",
46
47
  "@types/node": "^14.0.10 || ^16.0.0",
47
48
  "@types/node-fetch": "^2.5.7",
48
49
  "@types/pretty-hrtime": "^1.0.0",
@@ -53,7 +54,6 @@
53
54
  "commander": "^6.2.1",
54
55
  "compression": "^1.7.4",
55
56
  "core-js": "^3.8.2",
56
- "cpy": "^8.1.2",
57
57
  "detect-port": "^1.3.0",
58
58
  "express": "^4.17.1",
59
59
  "fs-extra": "^9.0.1",
@@ -77,7 +77,7 @@
77
77
  "x-default-browser": "^0.4.0"
78
78
  },
79
79
  "devDependencies": {
80
- "@storybook/builder-webpack5": "7.0.0-alpha.4",
80
+ "@storybook/builder-webpack5": "7.0.0-alpha.7",
81
81
  "@types/compression": "^1.7.0",
82
82
  "@types/ip": "^1.1.0",
83
83
  "@types/serve-favicon": "^2.5.2",
@@ -102,5 +102,5 @@
102
102
  "publishConfig": {
103
103
  "access": "public"
104
104
  },
105
- "gitHead": "006ed54452dd7c37a8cbe91a84f5312182f7ca00"
105
+ "gitHead": "d334cabd251cd0ed8b845a87707dc84f007d4074"
106
106
  }
package/typings.d.ts DELETED
@@ -1,13 +0,0 @@
1
- declare module 'global';
2
- declare module '@storybook/semver';
3
- declare module 'lazy-universal-dotenv';
4
- declare module 'pnp-webpack-plugin';
5
- declare module '@storybook/theming/paths';
6
- declare module '@storybook/ui/paths';
7
- declare module 'better-opn';
8
- declare module 'open';
9
- declare module 'x-default-browser';
10
- declare module '@storybook/ui';
11
- declare module '@discoveryjs/json-ext';
12
- declare module 'watchpack';
13
-