@weasel-js/forge 1.16.0 → 1.16.2

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.
Files changed (35) hide show
  1. package/README.md +14 -0
  2. package/dist/{FrameController-BM6xuEfY.d.ts → FrameController-DQTN1ytP.d.ts} +4 -1
  3. package/dist/{chunk-PPB7VP6R.js → chunk-5B4RDEF3.js} +87 -7
  4. package/dist/chunk-5B4RDEF3.js.map +1 -0
  5. package/dist/{chunk-MRYXJTDO.js → chunk-7YVJS4QS.js} +3 -3
  6. package/dist/{chunk-MRYXJTDO.js.map → chunk-7YVJS4QS.js.map} +1 -1
  7. package/dist/{chunk-PGLOYXDP.js → chunk-EVPVBDHM.js} +31 -5
  8. package/dist/chunk-EVPVBDHM.js.map +1 -0
  9. package/dist/{chunk-SZ2SMRE6.js → chunk-KNBEHCFD.js} +3 -29
  10. package/dist/chunk-KNBEHCFD.js.map +1 -0
  11. package/dist/{chunk-5WS67HMU.js → chunk-PN4IFL5E.js} +6 -3
  12. package/dist/chunk-PN4IFL5E.js.map +1 -0
  13. package/dist/{chunk-RVJHUY7W.js → chunk-ZGELUE2H.js} +3 -3
  14. package/dist/{chunk-RVJHUY7W.js.map → chunk-ZGELUE2H.js.map} +1 -1
  15. package/dist/{config-DOjWyIui.d.ts → config-BaC0Cbyj.d.ts} +3 -2
  16. package/dist/frame/index.css +100 -0
  17. package/dist/frame/index.css.map +1 -1
  18. package/dist/frame/index.d.ts +9 -6
  19. package/dist/frame/index.js +4 -4
  20. package/dist/index.d.ts +5 -4
  21. package/dist/{mountFrame-CRPAjg1M.d.ts → mountFrame-CrIdX6nD.d.ts} +3 -2
  22. package/dist/shell/index.css +100 -0
  23. package/dist/shell/index.css.map +1 -1
  24. package/dist/shell/index.d.ts +8 -5
  25. package/dist/shell/index.js +7 -7
  26. package/dist/test/index.d.ts +3 -2
  27. package/dist/test/index.js +3 -3
  28. package/dist/vite/index.d.ts +7 -1
  29. package/dist/vite/index.js +272 -56
  30. package/dist/vite/index.js.map +1 -1
  31. package/package.json +15 -12
  32. package/dist/chunk-5WS67HMU.js.map +0 -1
  33. package/dist/chunk-PGLOYXDP.js.map +0 -1
  34. package/dist/chunk-PPB7VP6R.js.map +0 -1
  35. package/dist/chunk-SZ2SMRE6.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { CAPTURE_PAGES, DEFAULT_TITLE, ISSUES_PATH, CAPTURE_PATH, issueLabel, parsePayload, messageOf } from '../chunk-MRYXJTDO.js';
2
- import { byComponent } from '../chunk-RVJHUY7W.js';
1
+ import { CAPTURE_PAGES, DEFAULT_TITLE, ISSUES_PATH, CAPTURE_PATH, issueLabel, parsePayload, messageOf } from '../chunk-7YVJS4QS.js';
2
+ import { byComponent } from '../chunk-ZGELUE2H.js';
3
3
  import { isGallery } from '../chunk-VUPN73JP.js';
4
- import { PROP_ARG_TYPES_EXPORT, storyNameFromExport, storyId } from '../chunk-5WS67HMU.js';
4
+ import { PROP_ARG_TYPES_EXPORT, API_EXPORT, storyNameFromExport, storyId } from '../chunk-PN4IFL5E.js';
5
5
  import { readFileSync, mkdtempSync, existsSync, mkdirSync, writeFileSync, globSync, statSync, watch, rmSync } from 'fs';
6
6
  import { resolve, relative, sep, isAbsolute, join, dirname, basename, matchesGlob, posix } from 'path';
7
7
  import { parse } from '@babel/parser';
@@ -55,6 +55,68 @@ function hoistPages(bundle, emit) {
55
55
  emit({ type: "asset", fileName: `${name}.html`, source: up(asset.source) });
56
56
  }
57
57
  }
58
+
59
+ // src/vite/componentOf.ts
60
+ var titleStandIn = (title) => title.split("/").pop()?.replace(/\s+/g, "");
61
+ function componentOf(tsm, checker, source, fallback) {
62
+ const module = checker.getSymbolAtLocation(source);
63
+ const exported = module && checker.tryGetMemberInModuleExports("default", module);
64
+ if (!exported) return null;
65
+ const meta = checker.getTypeOfSymbolAtLocation(resolved(tsm, checker, exported), source);
66
+ let named = meta.getProperty("component");
67
+ let symbol = named && assigned(tsm, checker, resolved(tsm, checker, exported));
68
+ const local = !symbol || symbol.getDeclarations()?.some((declaration2) => declaration2.getSourceFile() === source);
69
+ const imported = local && fallback ? importNamed(tsm, checker, source, fallback) : void 0;
70
+ if (imported) {
71
+ named = void 0;
72
+ symbol = imported;
73
+ }
74
+ if (!named && !symbol) return null;
75
+ const type = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(symbol ?? named, source));
76
+ const declaration = symbol?.getDeclarations()?.[0];
77
+ for (const part of type.isUnion() ? type.types : [type]) {
78
+ const [call] = part.getCallSignatures();
79
+ const [param] = call?.getParameters() ?? [];
80
+ if (call) return { props: param ? checker.getTypeOfSymbolAtLocation(param, source) : null, declaration };
81
+ const instance = part.getConstructSignatures()[0]?.getReturnType();
82
+ const held = instance?.getProperty("props");
83
+ if (held) return { props: checker.getTypeOfSymbolAtLocation(held, source), declaration };
84
+ }
85
+ return null;
86
+ }
87
+ var resolved = (tsm, checker, symbol) => symbol.flags & tsm.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
88
+ function assigned(tsm, checker, meta) {
89
+ const declaration = meta.getDeclarations()?.[0];
90
+ let node = declaration && tsm.isVariableDeclaration(declaration) ? declaration.initializer : declaration && tsm.isExportAssignment(declaration) ? declaration.expression : void 0;
91
+ while (node && !tsm.isObjectLiteralExpression(node)) {
92
+ if (tsm.isCallExpression(node)) node = node.arguments[0];
93
+ else if (tsm.isParenthesizedExpression(node) || tsm.isAsExpression(node) || tsm.isSatisfiesExpression(node)) {
94
+ node = node.expression;
95
+ } else node = void 0;
96
+ }
97
+ const property = node?.properties.find((p) => p.name && tsm.isIdentifier(p.name) && p.name.text === "component");
98
+ let value;
99
+ if (property && tsm.isShorthandPropertyAssignment(property)) value = checker.getShorthandAssignmentValueSymbol(property);
100
+ else if (property && tsm.isPropertyAssignment(property)) value = checker.getSymbolAtLocation(property.initializer);
101
+ return value && resolved(tsm, checker, value);
102
+ }
103
+ function importNamed(tsm, checker, source, name) {
104
+ for (const statement of source.statements) {
105
+ if (!tsm.isImportDeclaration(statement)) continue;
106
+ const clause = statement.importClause;
107
+ const bindings = clause?.namedBindings;
108
+ const names = [
109
+ ...clause?.name ? [clause.name] : [],
110
+ ...bindings && tsm.isNamedImports(bindings) ? bindings.elements.map((element) => element.name) : []
111
+ ];
112
+ const found = names.find((id) => id.text === name);
113
+ const symbol = found && checker.getSymbolAtLocation(found);
114
+ if (symbol) return resolved(tsm, checker, symbol);
115
+ }
116
+ return void 0;
117
+ }
118
+
119
+ // src/vite/depGraph.ts
58
120
  var keyOf = (file, local) => `${file}#${local}`;
59
121
  var fileOfKey = (key) => key.slice(0, key.lastIndexOf("#"));
60
122
  var SCRIPT = /\.[cm]?[jt]sx?$/;
@@ -130,10 +192,10 @@ function createDepGraph({ root, read }) {
130
192
  const target = await resolveFrom(imp.spec, importer);
131
193
  return target ? declaring(target, imp.imported, depth) : null;
132
194
  };
133
- const componentOf = async (entry) => {
195
+ const componentOf2 = async (entry) => {
134
196
  const mod = info(entry.file);
135
197
  if (!mod) return null;
136
- const byTitle = entry.title.split("/").pop()?.replace(/\s+/g, "");
198
+ const byTitle = titleStandIn(entry.title);
137
199
  for (const local of [entry.componentName, byTitle]) {
138
200
  const imp = local ? mod.imports.get(local) : void 0;
139
201
  const key = imp ? await importKey(entry.file, imp) : null;
@@ -153,7 +215,7 @@ function createDepGraph({ root, read }) {
153
215
  for (const [title, list] of titles) {
154
216
  let key = null;
155
217
  for (const file of new Set(list.map((e) => e.file))) {
156
- key = await componentOf(list.find((e) => e.file === file));
218
+ key = await componentOf2(list.find((e) => e.file === file));
157
219
  if (key) break;
158
220
  }
159
221
  components.set(title, key);
@@ -929,9 +991,9 @@ function createWrapperResolver(read) {
929
991
  }
930
992
 
931
993
  // src/vite/indexStory.ts
932
- function indexStory(code, file, source, resolved) {
933
- const foreign = resolved ? foreignFrom(resolved.foreign) : void 0;
934
- return indexFile(code, file, autoTitle(file, source.root, source.stories), resolved?.wrappers, foreign);
994
+ function indexStory(code, file, source, resolved2) {
995
+ const foreign = resolved2 ? foreignFrom(resolved2.foreign) : void 0;
996
+ return indexFile(code, file, autoTitle(file, source.root, source.stories), resolved2?.wrappers, foreign);
935
997
  }
936
998
  async function indexStoryResolved(code, file, source, resolve6, decide = createWrapperResolver((path) => readFileSync(path, "utf8"))) {
937
999
  const resolution = await decide(file, foreignCallees(code, file), resolve6);
@@ -949,15 +1011,146 @@ function ownEntries(realms) {
949
1011
  }
950
1012
  return [];
951
1013
  }
1014
+
1015
+ // src/vite/apiTable.ts
1016
+ var RESERVED = /* @__PURE__ */ new Set(["ref", "key"]);
1017
+ var IN_PACKAGES = /[\\/]node_modules[\\/]/;
1018
+ function apiTable(reading, declaration, props) {
1019
+ const { checker } = reading;
1020
+ const sources = /* @__PURE__ */ new Set();
1021
+ const record2 = (symbol) => {
1022
+ for (const file of filesOf(symbol)) if (!IN_PACKAGES.test(file)) sources.add(file);
1023
+ };
1024
+ const defaults = declaration ? destructuredDefaults(reading.tsm, declaration) : /* @__PURE__ */ new Map();
1025
+ const listed = [];
1026
+ const inherited = /* @__PURE__ */ new Map();
1027
+ let ref = null;
1028
+ for (const prop2 of props ? checker.getPropertiesOfType(checker.getApparentType(props)) : []) {
1029
+ const name = prop2.getName();
1030
+ if (name === "ref") ref = refOf(reading, prop2, record2);
1031
+ if (RESERVED.has(name)) continue;
1032
+ const files = filesOf(prop2);
1033
+ if (files.length > 0 && files.every(reading.skipped)) {
1034
+ const from = containerName(reading.tsm, prop2) ?? packageOf2(files[0]);
1035
+ inherited.set(from, (inherited.get(from) ?? 0) + 1);
1036
+ continue;
1037
+ }
1038
+ listed.push(propEntry(reading, prop2, defaults.get(name)));
1039
+ record2(prop2);
1040
+ }
1041
+ return {
1042
+ props: listed,
1043
+ inherited: [...inherited].map(([from, count]) => ({ from, count })),
1044
+ ref,
1045
+ sources: [...sources]
1046
+ };
1047
+ }
1048
+ var filesOf = (symbol) => (symbol.getDeclarations() ?? []).map((declaration) => declaration.getSourceFile().fileName);
1049
+ var docOf2 = ({ tsm, checker }, symbol) => tsm.displayPartsToString(symbol.getDocumentationComment(checker)).replace(/\s+/g, " ").trim();
1050
+ function tagText({ tsm, checker }, symbol, names) {
1051
+ const tag = symbol.getJsDocTags(checker).find((t) => names.includes(t.name));
1052
+ return tag ? tsm.displayPartsToString(tag.text).trim() : void 0;
1053
+ }
1054
+ function propEntry(reading, prop2, destructured) {
1055
+ const entry = {
1056
+ name: prop2.getName(),
1057
+ type: writtenType(reading, prop2),
1058
+ required: !(prop2.flags & reading.tsm.SymbolFlags.Optional)
1059
+ };
1060
+ const fallback = destructured ?? tagText(reading, prop2, ["default", "defaultValue"]);
1061
+ if (fallback) entry.default = fallback;
1062
+ const description = docOf2(reading, prop2);
1063
+ if (description) entry.description = description;
1064
+ const deprecated = tagText(reading, prop2, ["deprecated"]);
1065
+ if (deprecated !== void 0) entry.deprecated = deprecated;
1066
+ return entry;
1067
+ }
1068
+ function writtenType({ tsm, checker, at }, symbol) {
1069
+ const type = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(symbol, at));
1070
+ const [declaration, ...others] = symbol.getDeclarations() ?? [];
1071
+ const node = declaration && others.length === 0 && tsm.isPropertySignature(declaration) ? declaration.type : void 0;
1072
+ if (node && checker.getNonNullableType(checker.getTypeFromTypeNode(node)) === type) return node.getText().replace(/\s+/g, " ");
1073
+ return checker.typeToString(type, void 0, tsm.TypeFormatFlags.NoTruncation);
1074
+ }
1075
+ function packageOf2(file) {
1076
+ const parts = file.split(/[\\/]/);
1077
+ const at = parts.lastIndexOf("node_modules");
1078
+ if (at < 0 || at + 1 >= parts.length) return parts.at(-1) ?? file;
1079
+ const name = parts[at + 1];
1080
+ return name.startsWith("@") && parts[at + 2] ? `${name}/${parts[at + 2]}` : name;
1081
+ }
1082
+ function containerName(tsm, prop2) {
1083
+ const parent = prop2.getDeclarations()?.[0]?.parent;
1084
+ if (!parent) return void 0;
1085
+ if (tsm.isInterfaceDeclaration(parent) || tsm.isClassDeclaration(parent)) return parent.name?.text;
1086
+ if (tsm.isTypeLiteralNode(parent) && tsm.isTypeAliasDeclaration(parent.parent)) return parent.parent.name.text;
1087
+ return void 0;
1088
+ }
1089
+ function refOf(reading, prop2, record2) {
1090
+ const { tsm, checker, at } = reading;
1091
+ const type = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(prop2, at));
1092
+ for (const part of type.isUnion() ? type.types : [type]) {
1093
+ const current = part.getProperty("current");
1094
+ if (!current) continue;
1095
+ const held = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(current, at));
1096
+ const name = checker.typeToString(held, void 0, tsm.TypeFormatFlags.NoTruncation);
1097
+ const declared = (held.getSymbol() ?? held.aliasSymbol)?.getDeclarations() ?? [];
1098
+ if (declared.length > 0 && declared.every((d) => reading.platform(d.getSourceFile().fileName))) {
1099
+ return { type: name, members: [] };
1100
+ }
1101
+ const members = checker.getPropertiesOfType(held).map((member) => {
1102
+ record2(member);
1103
+ return memberEntry(reading, member);
1104
+ });
1105
+ return { type: name, members };
1106
+ }
1107
+ return null;
1108
+ }
1109
+ function memberEntry(reading, member) {
1110
+ const { tsm, checker, at } = reading;
1111
+ const type = checker.getTypeOfSymbolAtLocation(member, at);
1112
+ const [call] = type.getCallSignatures();
1113
+ const declarations = member.getDeclarations() ?? [];
1114
+ const entry = {
1115
+ name: member.getName(),
1116
+ kind: call ? "method" : "property",
1117
+ signature: call ? checker.signatureToString(call, void 0, tsm.TypeFormatFlags.WriteArrowStyleSignature | tsm.TypeFormatFlags.NoTruncation) : checker.typeToString(type, void 0, tsm.TypeFormatFlags.NoTruncation),
1118
+ readonly: declarations.some((d) => (tsm.getCombinedModifierFlags(d) & tsm.ModifierFlags.Readonly) !== 0)
1119
+ };
1120
+ const description = docOf2(reading, member);
1121
+ if (description) entry.description = description;
1122
+ return entry;
1123
+ }
1124
+ function destructuredDefaults(tsm, declaration) {
1125
+ const defaults = /* @__PURE__ */ new Map();
1126
+ let node = tsm.isVariableDeclaration(declaration) ? declaration.initializer : declaration;
1127
+ while (node && (tsm.isCallExpression(node) || tsm.isParenthesizedExpression(node) || tsm.isAsExpression(node))) {
1128
+ node = tsm.isCallExpression(node) ? node.arguments[0] : node.expression;
1129
+ }
1130
+ if (!node || !(tsm.isArrowFunction(node) || tsm.isFunctionExpression(node) || tsm.isFunctionDeclaration(node))) {
1131
+ return defaults;
1132
+ }
1133
+ const pattern = node.parameters[0]?.name;
1134
+ if (!pattern || !tsm.isObjectBindingPattern(pattern)) return defaults;
1135
+ for (const element of pattern.elements) {
1136
+ const key = element.propertyName ?? element.name;
1137
+ if (element.initializer && tsm.isIdentifier(key)) defaults.set(key.text, element.initializer.getText());
1138
+ }
1139
+ return defaults;
1140
+ }
1141
+
1142
+ // src/vite/propTypes.ts
952
1143
  var PLATFORM = /[\\/]node_modules[\\/](@types[\\/]react(-dom)?|typescript)[\\/]/;
953
1144
  async function createPropReader(root, stories, { skip } = {}) {
954
- const skipped = (file) => PLATFORM.test(file) || skip?.(file) === true;
1145
+ const platform = (file) => PLATFORM.test(file);
1146
+ const skipped = (file) => platform(file) || skip?.(file) === true;
955
1147
  let tsm;
956
1148
  try {
957
1149
  tsm = (await import('typescript')).default;
958
1150
  } catch {
959
1151
  return null;
960
1152
  }
1153
+ if (typeof tsm.createLanguageService !== "function") return null;
961
1154
  const { sys } = tsm;
962
1155
  const configFile = tsm.findConfigFile(root, sys.fileExists);
963
1156
  const read = configFile ? tsm.readConfigFile(configFile, sys.readFile) : void 0;
@@ -990,38 +1183,29 @@ async function createPropReader(root, stories, { skip } = {}) {
990
1183
  getDirectories: sys.getDirectories
991
1184
  };
992
1185
  const service = tsm.createLanguageService(host, tsm.createDocumentRegistry());
1186
+ const sourceOf = (file) => {
1187
+ const program = service.getProgram();
1188
+ const source = program?.getSourceFile(file);
1189
+ return program && source ? { checker: program.getTypeChecker(), source } : null;
1190
+ };
993
1191
  return {
994
1192
  read(file) {
995
- const program = service.getProgram();
996
- const source = program?.getSourceFile(file);
997
- if (!program || !source) return null;
998
- const checker = program.getTypeChecker();
999
- const props = componentProps(tsm, checker, source);
1193
+ const found = sourceOf(file);
1194
+ if (!found) return null;
1195
+ const { checker, source } = found;
1196
+ const props = componentOf(tsm, checker, source)?.props;
1000
1197
  return props ? propTable(tsm, checker, props, source, skipped) : null;
1198
+ },
1199
+ api(file, fallback) {
1200
+ const found = sourceOf(file);
1201
+ if (!found) return null;
1202
+ const { checker, source } = found;
1203
+ const component = componentOf(tsm, checker, source, fallback);
1204
+ if (!component) return null;
1205
+ return apiTable({ tsm, checker, at: source, skipped, platform }, component.declaration, component.props);
1001
1206
  }
1002
1207
  };
1003
1208
  }
1004
- function componentProps(tsm, checker, source) {
1005
- const module = checker.getSymbolAtLocation(source);
1006
- const exported = module && checker.tryGetMemberInModuleExports("default", module);
1007
- if (!exported) return null;
1008
- const meta = checker.getTypeOfSymbolAtLocation(
1009
- exported.flags & tsm.SymbolFlags.Alias ? checker.getAliasedSymbol(exported) : exported,
1010
- source
1011
- );
1012
- const named = meta.getProperty("component");
1013
- if (!named) return null;
1014
- const component = checker.getNonNullableType(checker.getTypeOfSymbolAtLocation(named, source));
1015
- for (const part of component.isUnion() ? component.types : [component]) {
1016
- const [call] = part.getCallSignatures();
1017
- const [param] = call?.getParameters() ?? [];
1018
- if (call) return param ? checker.getTypeOfSymbolAtLocation(param, source) : null;
1019
- const instance = part.getConstructSignatures()[0]?.getReturnType();
1020
- const held = instance?.getProperty("props");
1021
- if (held) return checker.getTypeOfSymbolAtLocation(held, source);
1022
- }
1023
- return null;
1024
- }
1025
1209
  function propTable(tsm, checker, props, at, skipped) {
1026
1210
  const argTypes = {};
1027
1211
  const reading = { tsm, checker, at, skipped, sources: /* @__PURE__ */ new Set() };
@@ -1041,9 +1225,9 @@ function propTable(tsm, checker, props, at, skipped) {
1041
1225
  return { argTypes, sources: [...reading.sources] };
1042
1226
  }
1043
1227
  var declaredIn = (symbol) => (symbol.getDeclarations() ?? []).map((declaration) => declaration.getSourceFile().fileName);
1044
- var IN_PACKAGES = /[\\/]node_modules[\\/]/;
1228
+ var IN_PACKAGES2 = /[\\/]node_modules[\\/]/;
1045
1229
  function record({ sources }, files) {
1046
- for (const file of files) if (!IN_PACKAGES.test(file)) sources.add(file);
1230
+ for (const file of files) if (!IN_PACKAGES2.test(file)) sources.add(file);
1047
1231
  }
1048
1232
  function controlFor(reading, type, written) {
1049
1233
  const { TypeFlags } = reading.tsm;
@@ -1099,11 +1283,11 @@ function shapeOf(reading, type, depth) {
1099
1283
  if (whole.getCallSignatures().length > 0 || whole.getConstructSignatures().length > 0) return null;
1100
1284
  if (checker.getIndexInfosOfType(whole).length > 0) return null;
1101
1285
  const declared = (whole.getSymbol() ?? whole.aliasSymbol)?.getDeclarations() ?? [];
1102
- if (declared.some((declaration) => IN_PACKAGES.test(declaration.getSourceFile().fileName))) return null;
1286
+ if (declared.some((declaration) => IN_PACKAGES2.test(declaration.getSourceFile().fileName))) return null;
1103
1287
  const fields = {};
1104
1288
  for (const prop2 of checker.getPropertiesOfType(whole)) {
1105
1289
  const files = declaredIn(prop2);
1106
- if (files.some((file) => IN_PACKAGES.test(file) || reading.skipped(file))) return null;
1290
+ if (files.some((file) => IN_PACKAGES2.test(file) || reading.skipped(file))) return null;
1107
1291
  const field = shapeOf(reading, checker.getTypeOfSymbolAtLocation(prop2, reading.at), depth + 1);
1108
1292
  if (field) fields[prop2.getName()] = field;
1109
1293
  else if (!(prop2.flags & tsm.SymbolFlags.Optional)) return null;
@@ -1144,7 +1328,38 @@ function writtenOrder(tsm, checker, prop2) {
1144
1328
  }
1145
1329
 
1146
1330
  // src/vite/propControls.ts
1147
- function propControls(stories, options = {}) {
1331
+ var errorText = (err) => err instanceof Error ? err.message : String(err);
1332
+ function storyExports(reader, file, fallback, { controls, api }, warn) {
1333
+ let code = "";
1334
+ const sources = [];
1335
+ if (controls) {
1336
+ try {
1337
+ const table = reader.read(file);
1338
+ if (table && Object.keys(table.argTypes).length > 0) {
1339
+ code += `
1340
+ export const ${PROP_ARG_TYPES_EXPORT} = ${JSON.stringify(table.argTypes)};
1341
+ `;
1342
+ sources.push(...table.sources);
1343
+ }
1344
+ } catch (err) {
1345
+ warn(`could not read the props for ${file}: ${errorText(err)}`);
1346
+ }
1347
+ }
1348
+ if (api) {
1349
+ try {
1350
+ const read = reader.api(file, fallback);
1351
+ const table = read && { props: read.props, inherited: read.inherited, ref: read.ref };
1352
+ code += `
1353
+ export const ${API_EXPORT} = ${JSON.stringify(table)};
1354
+ `;
1355
+ if (read) sources.push(...read.sources);
1356
+ } catch (err) {
1357
+ warn(`could not read the API for ${file}: ${errorText(err)}`);
1358
+ }
1359
+ }
1360
+ return { code, sources };
1361
+ }
1362
+ function propControls(stories, fallbackOf, readings, options = {}) {
1148
1363
  let root = process.cwd();
1149
1364
  let reader = null;
1150
1365
  return {
@@ -1156,17 +1371,11 @@ function propControls(stories, options = {}) {
1156
1371
  async transform(code, id) {
1157
1372
  if (!stories().includes(id)) return void 0;
1158
1373
  const props = await (reader ??= createPropReader(root, stories, options));
1159
- let table = null;
1160
- try {
1161
- table = props?.read(id) ?? null;
1162
- } catch (err) {
1163
- this.warn(`could not read the props for ${id}: ${err instanceof Error ? err.message : String(err)}`);
1164
- }
1165
- if (!table || Object.keys(table.argTypes).length === 0) return void 0;
1166
- for (const source of table.sources) this.addWatchFile(source);
1167
- return { code: `${code}
1168
- export const ${PROP_ARG_TYPES_EXPORT} = ${JSON.stringify(table.argTypes)};
1169
- `, map: null };
1374
+ if (!props) return void 0;
1375
+ const added = storyExports(props, id, fallbackOf(id), readings, (message) => this.warn(message));
1376
+ if (!added.code) return void 0;
1377
+ for (const source of new Set(added.sources)) this.addWatchFile(source);
1378
+ return { code: code + added.code, map: null };
1170
1379
  }
1171
1380
  };
1172
1381
  }
@@ -1981,12 +2190,19 @@ function watchSources(server, { files, depGraph, reindex, redeps, logError }) {
1981
2190
  });
1982
2191
  }
1983
2192
  }
1984
- function companions(options, storyFiles) {
1985
- const { storybookShims: shims, propControls: controls } = options;
2193
+ function companions(options, files) {
2194
+ const { storybookShims: shims, propControls: controls, api } = options;
2195
+ const storyFiles = () => [...files().keys()];
2196
+ const fallbackOf = (file) => {
2197
+ const title = files().get(file)?.[0]?.title;
2198
+ return title === void 0 ? void 0 : titleStandIn(title);
2199
+ };
2200
+ const readings = { controls: controls !== false, api: api !== false };
2201
+ const narrowed = typeof controls === "object" ? controls : void 0;
1986
2202
  return [
1987
2203
  watchRecovery(),
1988
2204
  ...shims === false ? [] : [storybookShims()],
1989
- ...controls === false ? [] : [propControls(storyFiles, controls === true ? void 0 : controls)]
2205
+ ...readings.controls || readings.api ? [propControls(storyFiles, fallbackOf, readings, narrowed)] : []
1990
2206
  ];
1991
2207
  }
1992
2208
  function forge(options) {
@@ -2127,7 +2343,7 @@ function forge(options) {
2127
2343
  return true;
2128
2344
  }
2129
2345
  return [
2130
- ...companions(options, () => [...files().keys()]),
2346
+ ...companions(options, files),
2131
2347
  {
2132
2348
  name: "weaselforge",
2133
2349
  config(config, { command }) {