@sit-onyx/storybook-utils 1.0.0-beta.101 → 1.0.0-beta.103

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sit-onyx/storybook-utils",
3
3
  "description": "Storybook utilities for Vue",
4
- "version": "1.0.0-beta.101",
4
+ "version": "1.0.0-beta.103",
5
5
  "type": "module",
6
6
  "author": "Schwarz IT KG",
7
7
  "license": "Apache-2.0",
@@ -31,17 +31,18 @@
31
31
  "prettier": ">= 3.0.0",
32
32
  "storybook": ">= 9.0.0",
33
33
  "vue-component-type-helpers": ">= 2",
34
- "@sit-onyx/shared": "^1.0.0-beta.4",
35
- "@sit-onyx/icons": "^1.0.0-beta.23"
34
+ "@sit-onyx/flags": "^1.0.0-beta.7",
35
+ "@sit-onyx/icons": "^1.0.0-beta.25",
36
+ "@sit-onyx/shared": "^1.0.0-beta.4"
36
37
  },
37
38
  "dependencies": {
38
39
  "deepmerge-ts": "^7.1.5"
39
40
  },
40
41
  "devDependencies": {
41
- "storybook": "^9.0.18",
42
+ "storybook": "^9.1.1",
42
43
  "vue": "3.5.18",
43
- "vue-component-type-helpers": "^3.0.3",
44
- "@sit-onyx/icons": "^1.0.0-beta.23",
44
+ "vue-component-type-helpers": "^3.0.5",
45
+ "@sit-onyx/icons": "^1.0.0-beta.25",
45
46
  "@sit-onyx/shared": "^1.0.0-beta.4"
46
47
  },
47
48
  "scripts": {
@@ -1,3 +1,4 @@
1
+ import { flagDE } from "@sit-onyx/flags";
1
2
  import { iconBellRing, iconCalendar, iconPlaceholder } from "@sit-onyx/icons";
2
3
  import { describe, expect, test } from "vitest";
3
4
  import { replaceAll, sourceCodeTransformer } from "./preview.js";
@@ -6,7 +7,7 @@ describe("preview.ts", () => {
6
7
  test("should transform source code and add icon/onyx imports", async () => {
7
8
  // ACT
8
9
  const sourceCode = await sourceCodeTransformer(`<template>
9
- <OnyxTest icon='${iconPlaceholder}' test='${iconBellRing}' :obj="{foo:'${replaceAll(iconCalendar, '"', "\\'")}'}" />
10
+ <OnyxTest icon='${iconPlaceholder}' test='${iconBellRing}' :obj="{foo:'${replaceAll(iconCalendar, '"', "\\'")}'}" flag='${flagDE}' />
10
11
  <OnyxOtherComponent />
11
12
  <OnyxComp>Test</OnyxComp>
12
13
  </template>`);
@@ -15,6 +16,7 @@ describe("preview.ts", () => {
15
16
  expect(sourceCode).toBe(`<script lang="ts" setup>
16
17
  import { OnyxComp, OnyxOtherComponent, OnyxTest } from "sit-onyx";
17
18
  import { iconBellRing, iconCalendar, iconPlaceholder } from "@sit-onyx/icons";
19
+ import { flagDE } from "@sit-onyx/flags";
18
20
  </script>
19
21
 
20
22
  <template>
@@ -22,6 +24,7 @@ import { iconBellRing, iconCalendar, iconPlaceholder } from "@sit-onyx/icons";
22
24
  :icon="iconPlaceholder"
23
25
  :test="iconBellRing"
24
26
  :obj="{foo:iconCalendar}"
27
+ :flag="flagDE"
25
28
  />
26
29
  <OnyxOtherComponent />
27
30
  <OnyxComp>Test</OnyxComp>
package/src/preview.ts CHANGED
@@ -132,65 +132,89 @@ export const createPreview = <T extends Preview = Preview>(
132
132
  * @see https://storybook.js.org/docs/react/api/doc-block-source
133
133
  */
134
134
  export const sourceCodeTransformer = async (originalSourceCode: string): Promise<string> => {
135
- const ALL_ICONS = await import("@sit-onyx/icons");
136
-
137
135
  let code = originalSourceCode;
138
136
 
139
- const additionalImports: string[] = [];
140
-
141
- // add icon imports to the source code for all used onyx icons
142
- const usedIcons = new Set<string>();
143
-
144
- Object.entries(ALL_ICONS).forEach(([iconName, iconContent]) => {
145
- const singleQuotedIconContent = `'${replaceAll(iconContent, '"', "\\'")}'`;
146
- const escapedIconContent = `"${replaceAll(iconContent, '"', '\\"')}"`;
147
-
148
- if (code.includes(iconContent)) {
149
- usedIcons.add(iconName);
150
-
151
- code = code.replace(
152
- new RegExp(` (\\S+)=['"]${escapeRegExp(iconContent)}['"]`),
153
- ` :$1="${iconName}"`,
154
- );
155
- } else if (code.includes(singleQuotedIconContent)) {
156
- // support icons inside objects
157
- usedIcons.add(iconName);
158
- code = code.replace(singleQuotedIconContent, iconName);
159
- } else if (code.includes(escapedIconContent)) {
160
- // support icons inside objects
161
- usedIcons.add(iconName);
162
- code = code.replace(escapedIconContent, iconName);
163
- }
164
- });
165
-
166
- if (usedIcons.size > 0) {
167
- additionalImports.push(
168
- `import { ${Array.from(usedIcons.values()).sort().join(", ")} } from "@sit-onyx/icons";`,
169
- );
170
- }
137
+ /**
138
+ * A list of additional JavaScript imports to be added at the top of the source code.
139
+ *
140
+ * key = module/package name to import from, value: set of imports to import from the package
141
+ */
142
+ const additionalImports = new Map<string, Set<string>>();
171
143
 
172
144
  // add imports for all used onyx components
173
145
  // Set is used here to only include unique components if they are used multiple times
174
- const usedOnyxComponents = [
175
- ...new Set(Array.from(code.matchAll(/<(Onyx\w+)(?:\s*\/?)/g)).map((match) => match[1])),
176
- ].sort();
146
+ const usedOnyxComponents = new Set(
147
+ Array.from(code.matchAll(/<(Onyx\w+)(?:\s*\/?)/g)).map((match) => match[1]),
148
+ );
149
+ additionalImports.set("sit-onyx", usedOnyxComponents);
177
150
 
178
- if (usedOnyxComponents.length > 0) {
179
- additionalImports.unshift(`import { ${usedOnyxComponents.join(", ")} } from "sit-onyx";`);
180
- }
151
+ /**
152
+ * List of npm packages to replace the source code with.
153
+ * The source code will be checked for any import of the package and (if its used), the code will be replaced by the corresponding import.
154
+ */
155
+ const packagesToReplace = [
156
+ { name: "@sit-onyx/icons", data: await import("@sit-onyx/icons") },
157
+ { name: "@sit-onyx/flags", data: await import("@sit-onyx/flags") },
158
+ ];
159
+
160
+ packagesToReplace.forEach((_package) => {
161
+ Object.entries(_package.data).forEach(([name, content]) => {
162
+ const singleQuotedContent = `'${replaceAll(content, '"', "\\'")}'`;
163
+ const escapedContent = `"${replaceAll(content, '"', '\\"')}"`;
164
+
165
+ const imports = additionalImports.get(_package.name) ?? new Set<string>();
166
+
167
+ if (code.includes(content)) {
168
+ imports.add(name);
169
+
170
+ code = code.replace(
171
+ new RegExp(` (\\S+)=['"]${escapeRegExp(content)}['"]`),
172
+ ` :$1="${name}"`,
173
+ );
174
+ } else if (code.includes(singleQuotedContent)) {
175
+ // support values inside objects
176
+ imports.add(name);
177
+ code = code.replace(singleQuotedContent, name);
178
+ } else if (code.includes(escapedContent)) {
179
+ // support values inside objects
180
+ imports.add(name);
181
+ code = code.replace(escapedContent, name);
182
+ }
183
+
184
+ additionalImports.set(_package.name, imports);
185
+ });
186
+ });
187
+
188
+ // remove imports without any data so we don't add empty imports
189
+ additionalImports.forEach((value, key) => {
190
+ if (!value.size) additionalImports.delete(key);
191
+ });
192
+
193
+ // generate the source code for the additional imports and add them to the top of the code snippet
194
+ if (additionalImports.size > 0) {
195
+ const additionalImportsCode = Array.from(additionalImports.entries()).reduce(
196
+ (code, [packageName, imports]) => {
197
+ if (imports.size) {
198
+ code.push(
199
+ `import { ${Array.from(imports.values()).sort().join(", ")} } from "${packageName}";`,
200
+ );
201
+ }
202
+ return code;
203
+ },
204
+ [] as string[],
205
+ );
181
206
 
182
- if (additionalImports.length > 1) {
183
207
  if (code.startsWith("<script")) {
184
208
  const index = code.indexOf("\n");
185
209
  const hasOtherImports = code.includes("import {");
186
210
  code =
187
211
  code.slice(0, index) +
188
- additionalImports.join("\n") +
212
+ additionalImportsCode.join("\n") +
189
213
  (!hasOtherImports ? "\n" : "") +
190
214
  code.slice(index);
191
215
  } else {
192
216
  code = `<script lang="ts" setup>
193
- ${additionalImports.join("\n")}
217
+ ${additionalImportsCode.join("\n")}
194
218
  </script>
195
219
 
196
220
  ${code}`;