storyblok 4.14.3 → 4.15.0
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.
- package/dist/index.mjs +188 -30
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -5299,6 +5299,121 @@ const storyblokSchemas = /* @__PURE__ */ new Map([
|
|
|
5299
5299
|
["richtext", getRichtextJSONSchema]
|
|
5300
5300
|
]);
|
|
5301
5301
|
|
|
5302
|
+
function generateStoryblokImports(storyblokPropertyTypes, STORY_TYPE) {
|
|
5303
|
+
const imports = [];
|
|
5304
|
+
const needsISbStoryData = storyblokPropertyTypes.has(STORY_TYPE);
|
|
5305
|
+
if (needsISbStoryData) {
|
|
5306
|
+
imports.push(`import type { ${STORY_TYPE} } from '@storyblok/js';`);
|
|
5307
|
+
storyblokPropertyTypes.delete(STORY_TYPE);
|
|
5308
|
+
}
|
|
5309
|
+
if (storyblokPropertyTypes.size > 0) {
|
|
5310
|
+
const typeImports = Array.from(storyblokPropertyTypes).map((type) => {
|
|
5311
|
+
const pascalType = toPascalCase(type);
|
|
5312
|
+
return `Storyblok${pascalType}`;
|
|
5313
|
+
});
|
|
5314
|
+
imports.push(`import type { ${typeImports.join(", ")} } from '../storyblok.d.ts';`);
|
|
5315
|
+
}
|
|
5316
|
+
return imports;
|
|
5317
|
+
}
|
|
5318
|
+
function escapeRegExp(value) {
|
|
5319
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5320
|
+
}
|
|
5321
|
+
function hasIdentifier(content, identifier) {
|
|
5322
|
+
const regex = new RegExp(`\\b${escapeRegExp(identifier)}\\b`, "g");
|
|
5323
|
+
return regex.test(content);
|
|
5324
|
+
}
|
|
5325
|
+
function detectUsedStoryblokTypes(content, storyblokPropertyTypes, STORY_TYPE) {
|
|
5326
|
+
const usedTypes = [];
|
|
5327
|
+
if (content.includes(STORY_TYPE)) {
|
|
5328
|
+
usedTypes.push(STORY_TYPE);
|
|
5329
|
+
}
|
|
5330
|
+
Array.from(storyblokPropertyTypes).forEach((type) => {
|
|
5331
|
+
const pascalType = toPascalCase(type);
|
|
5332
|
+
if (content.includes(`Storyblok${pascalType}`)) {
|
|
5333
|
+
usedTypes.push(type);
|
|
5334
|
+
}
|
|
5335
|
+
});
|
|
5336
|
+
return usedTypes;
|
|
5337
|
+
}
|
|
5338
|
+
function detectUsedDatasourceTypes(content, datasourceResults) {
|
|
5339
|
+
return datasourceResults.filter((ds) => hasIdentifier(content, ds.title)).map((ds) => ds.title);
|
|
5340
|
+
}
|
|
5341
|
+
function detectReferencedComponents(content, currentTitle, componentResults) {
|
|
5342
|
+
return componentResults.filter((c) => c.title !== currentTitle && hasIdentifier(content, c.title)).map((c) => c.title);
|
|
5343
|
+
}
|
|
5344
|
+
function generateComponentImports(componentContent, componentTitle, storyblokPropertyTypes, datasourceResults, componentResults, STORY_TYPE) {
|
|
5345
|
+
const imports = [];
|
|
5346
|
+
const usedStoryblokTypes = detectUsedStoryblokTypes(
|
|
5347
|
+
componentContent,
|
|
5348
|
+
storyblokPropertyTypes,
|
|
5349
|
+
STORY_TYPE
|
|
5350
|
+
);
|
|
5351
|
+
if (usedStoryblokTypes.length > 0) {
|
|
5352
|
+
const hasISbStoryData = usedStoryblokTypes.includes(STORY_TYPE);
|
|
5353
|
+
const otherTypes = usedStoryblokTypes.filter((t) => t !== STORY_TYPE);
|
|
5354
|
+
if (hasISbStoryData) {
|
|
5355
|
+
imports.push(`import type { ${STORY_TYPE} } from '@storyblok/js';`);
|
|
5356
|
+
}
|
|
5357
|
+
if (otherTypes.length > 0) {
|
|
5358
|
+
const typeImports = otherTypes.map((type) => {
|
|
5359
|
+
const pascalType = toPascalCase(type);
|
|
5360
|
+
return `Storyblok${pascalType}`;
|
|
5361
|
+
});
|
|
5362
|
+
imports.push(`import type { ${typeImports.join(", ")} } from '../storyblok.d.ts';`);
|
|
5363
|
+
}
|
|
5364
|
+
}
|
|
5365
|
+
const usedDatasourceTypes = detectUsedDatasourceTypes(componentContent, datasourceResults);
|
|
5366
|
+
if (usedDatasourceTypes.length > 0) {
|
|
5367
|
+
imports.push(`import type { ${usedDatasourceTypes.join(", ")} } from './datasource-types.d.ts';`);
|
|
5368
|
+
}
|
|
5369
|
+
const referencedComponents = detectReferencedComponents(
|
|
5370
|
+
componentContent,
|
|
5371
|
+
componentTitle,
|
|
5372
|
+
componentResults
|
|
5373
|
+
);
|
|
5374
|
+
if (referencedComponents.length > 0) {
|
|
5375
|
+
const componentImportsStr = referencedComponents.map((name) => `import type { ${name} } from './${name}.d.ts';`).join("\n");
|
|
5376
|
+
imports.push(componentImportsStr);
|
|
5377
|
+
}
|
|
5378
|
+
return imports;
|
|
5379
|
+
}
|
|
5380
|
+
function createDatasourcesFile(datasourceResults, typeDefs) {
|
|
5381
|
+
if (datasourceResults.length === 0) {
|
|
5382
|
+
return null;
|
|
5383
|
+
}
|
|
5384
|
+
const content = [
|
|
5385
|
+
...typeDefs,
|
|
5386
|
+
...datasourceResults.map((r) => r.content)
|
|
5387
|
+
].join("\n");
|
|
5388
|
+
return { name: "datasource-types", content };
|
|
5389
|
+
}
|
|
5390
|
+
function createContentTypesFile(contentTypeBloks, typeDefs) {
|
|
5391
|
+
if (contentTypeBloks.size === 0) {
|
|
5392
|
+
return null;
|
|
5393
|
+
}
|
|
5394
|
+
const contentTypeNames = Array.from(contentTypeBloks);
|
|
5395
|
+
const imports = contentTypeNames.map((name) => `import type { ${name} } from './${name}.d.ts';`).join("\n");
|
|
5396
|
+
const typeUnion = contentTypeNames.length > 0 ? contentTypeNames.join("\n | ") : "never";
|
|
5397
|
+
const typeDefinition = `export type ContentType =
|
|
5398
|
+
| ${typeUnion};`;
|
|
5399
|
+
const content = [
|
|
5400
|
+
...typeDefs,
|
|
5401
|
+
imports,
|
|
5402
|
+
typeDefinition
|
|
5403
|
+
].join("\n");
|
|
5404
|
+
return { name: "content-types", content };
|
|
5405
|
+
}
|
|
5406
|
+
function createComponentFile(componentResult, typeDefs, componentImports) {
|
|
5407
|
+
return {
|
|
5408
|
+
name: componentResult.title,
|
|
5409
|
+
content: [
|
|
5410
|
+
...typeDefs,
|
|
5411
|
+
...componentImports,
|
|
5412
|
+
componentResult.content
|
|
5413
|
+
].join("\n")
|
|
5414
|
+
};
|
|
5415
|
+
}
|
|
5416
|
+
|
|
5302
5417
|
const STORY_TYPE = "ISbStoryData";
|
|
5303
5418
|
const DEFAULT_COMPONENT_FILENAME = "storyblok-components";
|
|
5304
5419
|
const DEFAULT_TYPEDEFS_HEADER = [
|
|
@@ -5390,6 +5505,9 @@ const getComponentType = (componentName, options) => {
|
|
|
5390
5505
|
return isFirstCharacterNumber ? `_${componentType}` : componentType;
|
|
5391
5506
|
};
|
|
5392
5507
|
const getComponentPropertiesTypeAnnotations = async (component, options, spaceData, customFieldsParser) => {
|
|
5508
|
+
if (!component.schema || typeof component.schema !== "object") {
|
|
5509
|
+
return {};
|
|
5510
|
+
}
|
|
5393
5511
|
return Object.entries(component.schema).reduce(async (accPromise, [key, value]) => {
|
|
5394
5512
|
const acc = await accPromise;
|
|
5395
5513
|
if (key.startsWith("tab-")) {
|
|
@@ -5551,6 +5669,9 @@ const generateTypes = async (spaceData, options = {
|
|
|
5551
5669
|
const datasourcesSchema = spaceData.datasources.map(async (datasource) => {
|
|
5552
5670
|
const allComponentTypes = resolvedComponentsSchema.map((schema) => schema.title);
|
|
5553
5671
|
const enumValues = datasource.entries?.filter((d) => d.value).map((d) => d.value);
|
|
5672
|
+
if (!datasource.slug) {
|
|
5673
|
+
return null;
|
|
5674
|
+
}
|
|
5554
5675
|
const type = getDatasourceTypeTitle(datasource.slug);
|
|
5555
5676
|
if (allComponentTypes.includes(type)) {
|
|
5556
5677
|
console.warn(`Warning: Datasource type "${type}" conflicts with existing component type`);
|
|
@@ -5563,7 +5684,10 @@ const generateTypes = async (spaceData, options = {
|
|
|
5563
5684
|
};
|
|
5564
5685
|
return datasourceSchema;
|
|
5565
5686
|
});
|
|
5566
|
-
const
|
|
5687
|
+
const resolvedDatasourcesSchemaWithNulls = await Promise.all(datasourcesSchema);
|
|
5688
|
+
const resolvedDatasourcesSchema = resolvedDatasourcesSchemaWithNulls.filter((s) => s !== null);
|
|
5689
|
+
const componentTitles = new Set(resolvedComponentsSchema.map((s) => s.title).filter(Boolean));
|
|
5690
|
+
const datasourceTitles = new Set(resolvedDatasourcesSchema.map((s) => s.title).filter(Boolean));
|
|
5567
5691
|
const contentTypeSchema = {
|
|
5568
5692
|
$id: `#/ContentType`,
|
|
5569
5693
|
title: "ContentType",
|
|
@@ -5576,26 +5700,48 @@ const generateTypes = async (spaceData, options = {
|
|
|
5576
5700
|
contentTypeSchema
|
|
5577
5701
|
];
|
|
5578
5702
|
const result = await Promise.all(schemas.map(async (schema) => {
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5703
|
+
const title = schema.title || schema.$id.replace("#/", "");
|
|
5704
|
+
return {
|
|
5705
|
+
title,
|
|
5706
|
+
content: await compile(schema, title, {
|
|
5707
|
+
additionalProperties: !options.strict,
|
|
5708
|
+
bannerComment: "",
|
|
5709
|
+
...compilerOptions
|
|
5710
|
+
}),
|
|
5711
|
+
isComponent: componentTitles.has(title),
|
|
5712
|
+
isDatasource: datasourceTitles.has(title)
|
|
5713
|
+
};
|
|
5584
5714
|
}));
|
|
5585
|
-
const imports =
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5715
|
+
const imports = generateStoryblokImports(storyblokPropertyTypes, STORY_TYPE);
|
|
5716
|
+
if (options.separateFiles) {
|
|
5717
|
+
const files = [];
|
|
5718
|
+
const datasourceResults = result.filter((r) => r.isDatasource);
|
|
5719
|
+
const componentResults = result.filter((r) => r.isComponent);
|
|
5720
|
+
const datasourcesFile = createDatasourcesFile(datasourceResults, typeDefs);
|
|
5721
|
+
if (datasourcesFile) {
|
|
5722
|
+
files.push(datasourcesFile);
|
|
5723
|
+
}
|
|
5724
|
+
const contentTypesFile = createContentTypesFile(
|
|
5725
|
+
contentTypeBloks,
|
|
5726
|
+
typeDefs
|
|
5727
|
+
);
|
|
5728
|
+
if (contentTypesFile) {
|
|
5729
|
+
files.push(contentTypesFile);
|
|
5730
|
+
}
|
|
5731
|
+
for (const componentResult of componentResults) {
|
|
5732
|
+
const componentImports = generateComponentImports(
|
|
5733
|
+
componentResult.content,
|
|
5734
|
+
componentResult.title,
|
|
5735
|
+
storyblokPropertyTypes,
|
|
5736
|
+
datasourceResults,
|
|
5737
|
+
componentResults,
|
|
5738
|
+
STORY_TYPE
|
|
5739
|
+
);
|
|
5740
|
+
files.push(createComponentFile(componentResult, typeDefs, componentImports));
|
|
5741
|
+
}
|
|
5742
|
+
return files;
|
|
5597
5743
|
}
|
|
5598
|
-
const finalTypeDef = [...typeDefs, ...imports, ...result];
|
|
5744
|
+
const finalTypeDef = [...typeDefs, ...imports, ...result.map((r) => r.content)];
|
|
5599
5745
|
return [
|
|
5600
5746
|
...finalTypeDef
|
|
5601
5747
|
].join("\n");
|
|
@@ -5603,11 +5749,17 @@ const generateTypes = async (spaceData, options = {
|
|
|
5603
5749
|
handleError(error);
|
|
5604
5750
|
}
|
|
5605
5751
|
};
|
|
5606
|
-
const saveTypesToComponentsFile = async (space,
|
|
5607
|
-
const { filename = DEFAULT_COMPONENT_FILENAME, path } = options;
|
|
5752
|
+
const saveTypesToComponentsFile = async (space, typedefData, options) => {
|
|
5753
|
+
const { filename = DEFAULT_COMPONENT_FILENAME, path, separateFiles } = options;
|
|
5608
5754
|
const resolvedPath = path ? resolve$1(process.cwd(), path, "types", space) : resolvePath(path, `types/${space}`);
|
|
5609
5755
|
try {
|
|
5610
|
-
|
|
5756
|
+
if (separateFiles && Array.isArray(typedefData)) {
|
|
5757
|
+
for (const { name, content } of typedefData) {
|
|
5758
|
+
await saveToFile(join(resolvedPath, `${name}.d.ts`), content);
|
|
5759
|
+
}
|
|
5760
|
+
} else if (typeof typedefData === "string") {
|
|
5761
|
+
await saveToFile(join(resolvedPath, `${filename}.d.ts`), typedefData);
|
|
5762
|
+
}
|
|
5611
5763
|
} catch (error) {
|
|
5612
5764
|
handleFileSystemError("write", error);
|
|
5613
5765
|
}
|
|
@@ -5801,16 +5953,18 @@ generateCmd.action(async (options, command) => {
|
|
|
5801
5953
|
try {
|
|
5802
5954
|
spinner.start(`Generating types...`);
|
|
5803
5955
|
const componentsData = await readComponentsFiles({
|
|
5804
|
-
...options,
|
|
5805
5956
|
from: space,
|
|
5806
|
-
path
|
|
5957
|
+
path,
|
|
5958
|
+
suffix: options.suffix,
|
|
5959
|
+
verbose
|
|
5807
5960
|
});
|
|
5808
5961
|
let dataSourceData;
|
|
5809
5962
|
try {
|
|
5810
5963
|
dataSourceData = await readDatasourcesFiles({
|
|
5811
|
-
...options,
|
|
5812
5964
|
from: space,
|
|
5813
|
-
path
|
|
5965
|
+
path,
|
|
5966
|
+
suffix: options.suffix,
|
|
5967
|
+
verbose
|
|
5814
5968
|
});
|
|
5815
5969
|
} catch (error) {
|
|
5816
5970
|
if (error instanceof FileSystemError && error.errorId === "file_not_found") {
|
|
@@ -5826,17 +5980,21 @@ generateCmd.action(async (options, command) => {
|
|
|
5826
5980
|
...componentsData,
|
|
5827
5981
|
...dataSourceData
|
|
5828
5982
|
};
|
|
5829
|
-
const
|
|
5983
|
+
const typedefData = await generateTypes(spaceDataWithComponentsAndDatasources, {
|
|
5830
5984
|
...options,
|
|
5831
5985
|
path
|
|
5832
5986
|
});
|
|
5833
|
-
if (
|
|
5834
|
-
await saveTypesToComponentsFile(space,
|
|
5987
|
+
if (typedefData) {
|
|
5988
|
+
await saveTypesToComponentsFile(space, typedefData, {
|
|
5835
5989
|
filename: options.filename,
|
|
5836
|
-
path
|
|
5990
|
+
path,
|
|
5991
|
+
separateFiles: options.separateFiles
|
|
5837
5992
|
});
|
|
5838
5993
|
}
|
|
5839
5994
|
spinner.succeed();
|
|
5995
|
+
if (options.separateFiles && options.filename) {
|
|
5996
|
+
konsola.warn(`The --filename option is ignored when using --separate-files`);
|
|
5997
|
+
}
|
|
5840
5998
|
konsola.ok(`Successfully generated types for space ${space}`, true);
|
|
5841
5999
|
konsola.br();
|
|
5842
6000
|
} catch (error) {
|