uifork 0.0.10 → 0.0.11

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/cli.js CHANGED
@@ -6,6 +6,7 @@ const { UISwitcherScaffold } = require("./lib/init");
6
6
  const { VersionSync } = require("./lib/watch");
7
7
  const { VersionPromoter } = require("./lib/promote");
8
8
  const { findComponentManager } = require("./lib/cli-helpers");
9
+ const { getVersionComponentIdentifier } = require("./lib/component-naming");
9
10
 
10
11
  function showHelp() {
11
12
  console.log(`
@@ -230,8 +231,7 @@ switch (command) {
230
231
 
231
232
  const displayVersion = targetVersion.replace(/^v/, "").replace(/_/g, ".").toUpperCase();
232
233
 
233
- const importSuffix = manager.versionToImportSuffix(fileVersion);
234
- const componentName = `${manager.componentName}${importSuffix}`;
234
+ const componentName = getVersionComponentIdentifier(manager.componentName, fileVersion);
235
235
 
236
236
  let templateContent;
237
237
  if (extension === ".tsx" || extension === ".jsx") {
@@ -413,10 +413,11 @@ export default function ${componentName}() {
413
413
 
414
414
  const sourceContent = fs.readFileSync(sourceFilePath, "utf8");
415
415
 
416
- const importSuffix = manager.versionToImportSuffix(fileVersion);
417
- const newImportSuffix = manager.versionToImportSuffix(targetFileVersion);
418
- const oldComponentName = `${manager.componentName}${importSuffix}`;
419
- const newComponentName = `${manager.componentName}${newImportSuffix}`;
416
+ const oldComponentName = getVersionComponentIdentifier(manager.componentName, fileVersion);
417
+ const newComponentName = getVersionComponentIdentifier(
418
+ manager.componentName,
419
+ targetFileVersion,
420
+ );
420
421
 
421
422
  const updatedContent = sourceContent.replace(
422
423
  new RegExp(oldComponentName, "g"),
@@ -0,0 +1,30 @@
1
+ function toPascalCaseIdentifier(name) {
2
+ const chunks = String(name || "").match(/[a-zA-Z0-9]+/g) || [];
3
+ const identifier = chunks
4
+ .map((chunk) => `${chunk.charAt(0).toUpperCase()}${chunk.slice(1)}`)
5
+ .join("");
6
+
7
+ if (!identifier) {
8
+ return "Component";
9
+ }
10
+
11
+ if (!/^[A-Za-z_$]/.test(identifier)) {
12
+ return `Component${identifier}`;
13
+ }
14
+
15
+ return identifier;
16
+ }
17
+
18
+ function versionToImportSuffix(versionStr) {
19
+ return `V${versionStr.charAt(0).toUpperCase()}${versionStr.slice(1)}`;
20
+ }
21
+
22
+ function getVersionComponentIdentifier(componentName, versionStr) {
23
+ return `${toPascalCaseIdentifier(componentName)}${versionToImportSuffix(versionStr)}`;
24
+ }
25
+
26
+ module.exports = {
27
+ getVersionComponentIdentifier,
28
+ toPascalCaseIdentifier,
29
+ versionToImportSuffix,
30
+ };
package/lib/init.js CHANGED
@@ -1,6 +1,7 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
3
  const { VersionSync } = require("./watch");
4
+ const { toPascalCaseIdentifier } = require("./component-naming");
4
5
 
5
6
  class UISwitcherScaffold {
6
7
  constructor(filePath, shouldWatch = true) {
@@ -14,6 +15,7 @@ class UISwitcherScaffold {
14
15
 
15
16
  const parsedPath = path.parse(this.originalFilePath);
16
17
  this.componentName = parsedPath.name;
18
+ this.componentIdentifier = toPascalCaseIdentifier(this.componentName);
17
19
  this.parentDir = parsedPath.dir;
18
20
  this.originalExtension = parsedPath.ext; // Preserve .tsx or .ts
19
21
  this.v1File = path.join(this.parentDir, `${this.componentName}.v1${this.originalExtension}`);
@@ -38,11 +40,11 @@ class UISwitcherScaffold {
38
40
  * Manual edits to labels/descriptions are preserved, but structure changes may be overwritten.
39
41
  * To stop versioning this component, run: npx uifork promote ${this.componentName} <version-id>
40
42
  */
41
- import ${this.componentName}V1 from "${v1ImportPath}"
43
+ import ${this.componentIdentifier}V1 from "${v1ImportPath}"
42
44
 
43
45
  export const VERSIONS = {
44
46
  "v1": {
45
- render: ${this.componentName}V1,
47
+ render: ${this.componentIdentifier}V1,
46
48
  label: "",
47
49
  },
48
50
  }
@@ -65,7 +67,7 @@ export const VERSIONS = {
65
67
  import { ForkedComponent } from "uifork"
66
68
  import { VERSIONS } from "${versionsImportPath}"
67
69
 
68
- export default function ${this.componentName}(props: any) {
70
+ export default function ${this.componentIdentifier}(props: any) {
69
71
  return (
70
72
  <ForkedComponent
71
73
  id="${this.componentName}"
@@ -124,7 +126,7 @@ export { VERSIONS }
124
126
  `4. Add new versions by creating ${this.componentName}.v2${this.originalExtension}, ${this.componentName}.v1_1${this.originalExtension}, etc.`,
125
127
  );
126
128
  console.log(
127
- `5. Import the component: import ${this.componentName} from './${this.componentName}'`,
129
+ `5. Import the component: import ${this.componentIdentifier} from './${this.componentName}'`,
128
130
  );
129
131
  // Start watching automatically
130
132
  new VersionSync(this.parentDir);
@@ -134,7 +136,7 @@ export { VERSIONS }
134
136
  `4. Add new versions by creating ${this.componentName}.v2${this.originalExtension}, ${this.componentName}.v1_1${this.originalExtension}, etc.`,
135
137
  );
136
138
  console.log(
137
- `5. Import the component: import ${this.componentName} from './${this.componentName}'`,
139
+ `5. Import the component: import ${this.componentIdentifier} from './${this.componentName}'`,
138
140
  );
139
141
  }
140
142
  }
package/lib/promote.js CHANGED
@@ -1,5 +1,10 @@
1
1
  const fs = require("fs");
2
2
  const path = require("path");
3
+ const {
4
+ getVersionComponentIdentifier,
5
+ toPascalCaseIdentifier,
6
+ versionToImportSuffix,
7
+ } = require("./component-naming");
3
8
 
4
9
  class VersionPromoter {
5
10
  constructor(componentPath, versionId) {
@@ -190,8 +195,13 @@ class VersionPromoter {
190
195
  // Clean up the version content - remove version-specific naming if needed
191
196
  // The component name in the version file might be like ComponentNameV2
192
197
  // We want to replace it with just ComponentName
198
+ const baseComponentIdentifier = toPascalCaseIdentifier(this.componentName);
193
199
  const importSuffix = this.versionToImportSuffix(this.versionIdToFileVersion(this.versionId));
194
- const versionedComponentName = `${this.componentName}${importSuffix}`;
200
+ const versionedComponentName = getVersionComponentIdentifier(
201
+ this.componentName,
202
+ this.versionIdToFileVersion(this.versionId),
203
+ );
204
+ const legacyVersionedComponentName = `${this.componentName}${importSuffix}`;
195
205
 
196
206
  let cleanedContent = versionContent;
197
207
 
@@ -200,25 +210,41 @@ class VersionPromoter {
200
210
  // 1. export default function ComponentNameV2
201
211
  cleanedContent = cleanedContent.replace(
202
212
  new RegExp(`export default function ${versionedComponentName}\\b`, "g"),
203
- `export default function ${this.componentName}`,
213
+ `export default function ${baseComponentIdentifier}`,
214
+ );
215
+ cleanedContent = cleanedContent.replace(
216
+ new RegExp(`export default function ${legacyVersionedComponentName}\\b`, "g"),
217
+ `export default function ${baseComponentIdentifier}`,
204
218
  );
205
219
 
206
220
  // 2. function ComponentNameV2 (in case it's not exported yet)
207
221
  cleanedContent = cleanedContent.replace(
208
222
  new RegExp(`function ${versionedComponentName}\\b`, "g"),
209
- `function ${this.componentName}`,
223
+ `function ${baseComponentIdentifier}`,
224
+ );
225
+ cleanedContent = cleanedContent.replace(
226
+ new RegExp(`function ${legacyVersionedComponentName}\\b`, "g"),
227
+ `function ${baseComponentIdentifier}`,
210
228
  );
211
229
 
212
230
  // 3. const ComponentNameV2 = (arrow function)
213
231
  cleanedContent = cleanedContent.replace(
214
232
  new RegExp(`const ${versionedComponentName}\\s*=`, "g"),
215
- `const ${this.componentName} =`,
233
+ `const ${baseComponentIdentifier} =`,
234
+ );
235
+ cleanedContent = cleanedContent.replace(
236
+ new RegExp(`const ${legacyVersionedComponentName}\\s*=`, "g"),
237
+ `const ${baseComponentIdentifier} =`,
216
238
  );
217
239
 
218
240
  // 4. Any other references to the versioned component name
219
241
  cleanedContent = cleanedContent.replace(
220
242
  new RegExp(`\\b${versionedComponentName}\\b`, "g"),
221
- this.componentName,
243
+ baseComponentIdentifier,
244
+ );
245
+ cleanedContent = cleanedContent.replace(
246
+ new RegExp(`\\b${legacyVersionedComponentName}\\b`, "g"),
247
+ baseComponentIdentifier,
222
248
  );
223
249
 
224
250
  // Write the cleaned content to the wrapper file
@@ -230,7 +256,7 @@ class VersionPromoter {
230
256
 
231
257
  versionToImportSuffix(versionStr) {
232
258
  // Convert 1_2 to V1_2 for import names
233
- return `V${versionStr.charAt(0).toUpperCase()}${versionStr.slice(1)}`;
259
+ return versionToImportSuffix(versionStr);
234
260
  }
235
261
 
236
262
  promote() {
package/lib/watch.js CHANGED
@@ -7,6 +7,10 @@ const WebSocket = require("ws");
7
7
  const cors = require("cors");
8
8
  const { exec } = require("child_process");
9
9
  const { VersionPromoter } = require("./promote");
10
+ const {
11
+ getVersionComponentIdentifier,
12
+ versionToImportSuffix,
13
+ } = require("./component-naming");
10
14
 
11
15
  /**
12
16
  * ComponentManager - Manages a single component's versions
@@ -90,7 +94,7 @@ class ComponentManager {
90
94
  }
91
95
 
92
96
  versionToImportSuffix(versionStr) {
93
- return `V${versionStr.charAt(0).toUpperCase()}${versionStr.slice(1)}`;
97
+ return versionToImportSuffix(versionStr);
94
98
  }
95
99
 
96
100
  generateImportName(fileName) {
@@ -98,7 +102,7 @@ class ComponentManager {
98
102
  const match = fileName.match(versionPattern);
99
103
  if (!match) return null;
100
104
  const versionStr = match[1];
101
- return `${this.componentName}${this.versionToImportSuffix(versionStr)}`;
105
+ return getVersionComponentIdentifier(this.componentName, versionStr);
102
106
  }
103
107
 
104
108
  generateVersionKey(fileName) {
@@ -903,8 +907,7 @@ class VersionSync {
903
907
 
904
908
  const displayVersion = targetVersion.replace(/^v/, "").replace(/_/g, ".").toUpperCase();
905
909
 
906
- const importSuffix = manager.versionToImportSuffix(fileVersion);
907
- const componentName = `${manager.componentName}${importSuffix}`;
910
+ const componentName = getVersionComponentIdentifier(manager.componentName, fileVersion);
908
911
 
909
912
  let templateContent;
910
913
  if (extension === ".tsx" || extension === ".jsx") {
@@ -1029,10 +1032,11 @@ export default function ${componentName}() {
1029
1032
 
1030
1033
  const sourceContent = fs.readFileSync(sourceFilePath, "utf8");
1031
1034
 
1032
- const importSuffix = manager.versionToImportSuffix(fileVersion);
1033
- const newImportSuffix = manager.versionToImportSuffix(targetFileVersion);
1034
- const oldComponentName = `${manager.componentName}${importSuffix}`;
1035
- const newComponentName = `${manager.componentName}${newImportSuffix}`;
1035
+ const oldComponentName = getVersionComponentIdentifier(manager.componentName, fileVersion);
1036
+ const newComponentName = getVersionComponentIdentifier(
1037
+ manager.componentName,
1038
+ targetFileVersion,
1039
+ );
1036
1040
 
1037
1041
  let updatedContent = sourceContent.replace(
1038
1042
  new RegExp(oldComponentName, "g"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uifork",
3
- "version": "0.0.10",
3
+ "version": "0.0.11",
4
4
  "description": "CLI tool and React components for managing UI component versions and switching between them",
5
5
  "keywords": [
6
6
  "ab-testing",