@unisphere/nx 4.7.0 → 4.10.1

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 (33) hide show
  1. package/dist/generators/add-playground/add-playground.d.ts +5 -0
  2. package/dist/generators/add-playground/add-playground.d.ts.map +1 -0
  3. package/dist/generators/add-playground/add-playground.js +73 -0
  4. package/dist/generators/add-playground/schema.d.ts +5 -0
  5. package/dist/generators/add-playground/schema.json +29 -0
  6. package/dist/generators/add-playground/templates/react/playground.json.template +9 -0
  7. package/dist/generators/add-playground/templates/react/src/App.tsx.template +5 -0
  8. package/dist/generators/add-playground/templates/react/src/index.html.template +12 -0
  9. package/dist/generators/add-playground/templates/react/src/index.tsx.template +5 -0
  10. package/dist/generators/add-playground/templates/vanilla-js/playground.json.template +6 -0
  11. package/dist/generators/add-playground/templates/vanilla-js/src/index.html.template +12 -0
  12. package/dist/generators/add-playground/templates/vanilla-js/src/index.js.template +2 -0
  13. package/dist/generators/add-playground/templates/vanilla-ts/playground.json.template +6 -0
  14. package/dist/generators/add-playground/templates/vanilla-ts/src/index.html.template +12 -0
  15. package/dist/generators/add-playground/templates/vanilla-ts/src/index.ts.template +2 -0
  16. package/dist/migrations/4-10-1/add-get-workspace-to-get-service.d.ts +9 -0
  17. package/dist/migrations/4-10-1/add-get-workspace-to-get-service.d.ts.map +1 -0
  18. package/dist/migrations/4-10-1/add-get-workspace-to-get-service.js +54 -0
  19. package/dist/migrations/4-10-1/update-unisphere-visual-target.d.ts +10 -0
  20. package/dist/migrations/4-10-1/update-unisphere-visual-target.d.ts.map +1 -0
  21. package/dist/migrations/4-10-1/update-unisphere-visual-target.js +168 -0
  22. package/dist/migrations/4-10-1/wrap-tiny-data-store-initial-value.d.ts +9 -0
  23. package/dist/migrations/4-10-1/wrap-tiny-data-store-initial-value.d.ts.map +1 -0
  24. package/dist/migrations/4-10-1/wrap-tiny-data-store-initial-value.js +65 -0
  25. package/dist/migrations/4-11-0/migrate-analytics-types.d.ts +9 -0
  26. package/dist/migrations/4-11-0/migrate-analytics-types.d.ts.map +1 -0
  27. package/dist/migrations/4-11-0/migrate-analytics-types.js +102 -0
  28. package/dist/migrations/4-8-0/restore-security-audit-step.d.ts +3 -0
  29. package/dist/migrations/4-8-0/restore-security-audit-step.d.ts.map +1 -0
  30. package/dist/migrations/4-8-0/restore-security-audit-step.js +45 -0
  31. package/generators.json +5 -0
  32. package/migrations.json +74 -0
  33. package/package.json +1 -1
@@ -0,0 +1,5 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { AddPlaygroundGeneratorSchema } from './schema';
3
+ export declare function addPlaygroundGenerator(tree: Tree, options: AddPlaygroundGeneratorSchema): Promise<() => void>;
4
+ export default addPlaygroundGenerator;
5
+ //# sourceMappingURL=add-playground.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-playground.d.ts","sourceRoot":"","sources":["../../../src/generators/add-playground/add-playground.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAiB,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAC;AA6CxD,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,4BAA4B,uBAmDtC;AAED,eAAe,sBAAsB,CAAC"}
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addPlaygroundGenerator = addPlaygroundGenerator;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const utils_1 = require("../utils");
8
+ const VALID_ENGINES = ['vanilla-ts', 'vanilla-js', 'react'];
9
+ function validateOptions(options) {
10
+ if (!options.name || options.name.trim() === '') {
11
+ throw new Error(`Missing required option: 'name'\n` +
12
+ ` Description: The name of the playground to create\n` +
13
+ ` Type: string\n` +
14
+ ` Pattern: ^[a-zA-Z][a-zA-Z0-9\\-\\s]*$\n` +
15
+ ` Example: nx g @unisphere/nx:add-playground --name=my-demo --engine=react`);
16
+ }
17
+ const namePattern = /^[a-zA-Z][a-zA-Z0-9\-\s]*$/;
18
+ if (!namePattern.test(options.name)) {
19
+ throw new Error(`Invalid value '${options.name}' for option 'name'\n` +
20
+ ` Pattern: ^[a-zA-Z][a-zA-Z0-9\\-\\s]*$\n` +
21
+ ` Received: ${options.name}`);
22
+ }
23
+ if (!options.engine || !VALID_ENGINES.includes(options.engine)) {
24
+ throw new Error(`Invalid value '${options.engine}' for option 'engine'\n` +
25
+ ` Allowed values: ${VALID_ENGINES.join(', ')}\n` +
26
+ ` Example: nx g @unisphere/nx:add-playground --name=demo --engine=react`);
27
+ }
28
+ if (options.group) {
29
+ const groupPattern = /^[a-zA-Z0-9][a-zA-Z0-9\-_/]*$/;
30
+ if (!groupPattern.test(options.group)) {
31
+ throw new Error(`Invalid value '${options.group}' for option 'group'\n` +
32
+ ` Group path must contain only letters, numbers, hyphens, underscores, and forward slashes\n` +
33
+ ` Example: --group=getting-started or --group=advanced/hooks`);
34
+ }
35
+ }
36
+ }
37
+ async function addPlaygroundGenerator(tree, options) {
38
+ validateOptions(options);
39
+ // Ensure we're in a valid Unisphere workspace
40
+ (0, utils_1.validateUnisphereConfig)(tree);
41
+ const playgroundName = (0, devkit_1.names)(options.name).fileName;
42
+ const engine = options.engine;
43
+ // Build target path
44
+ const groupPath = options.group ? options.group.replace(/^\/|\/$/g, '') : '';
45
+ const targetDir = groupPath
46
+ ? `unisphere/playgrounds/${groupPath}/${playgroundName}`
47
+ : `unisphere/playgrounds/${playgroundName}`;
48
+ // Check if already exists
49
+ if (tree.exists(`${targetDir}/playground.json`)) {
50
+ throw new Error(`Playground already exists at "${targetDir}".\n` +
51
+ 'Please choose a different name or remove the existing playground first.');
52
+ }
53
+ // Template variables
54
+ const templateVars = {
55
+ ...(0, utils_1.createNameTransforms)(playgroundName, 'playgroundName'),
56
+ tmpl: '',
57
+ };
58
+ // Generate files from engine-specific templates
59
+ (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'templates', engine), targetDir, templateVars);
60
+ await (0, devkit_1.formatFiles)(tree);
61
+ return () => {
62
+ devkit_1.logger.info('');
63
+ devkit_1.logger.info('✅ Code playground created successfully!');
64
+ devkit_1.logger.info('');
65
+ devkit_1.logger.info(`📁 Location: ${targetDir}`);
66
+ devkit_1.logger.info(`🔧 Engine: ${engine}`);
67
+ if (groupPath) {
68
+ devkit_1.logger.info(`📂 Group: ${groupPath}`);
69
+ }
70
+ devkit_1.logger.info('');
71
+ };
72
+ }
73
+ exports.default = addPlaygroundGenerator;
@@ -0,0 +1,5 @@
1
+ export interface AddPlaygroundGeneratorSchema {
2
+ name: string;
3
+ group?: string;
4
+ engine: 'vanilla-ts' | 'vanilla-js' | 'react';
5
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "AddPlayground",
4
+ "title": "Add a code playground",
5
+ "description": "Scaffold a new code playground example",
6
+ "type": "object",
7
+ "properties": {
8
+ "name": {
9
+ "type": "string",
10
+ "description": "Playground name (letters, numbers, hyphens, spaces)",
11
+ "pattern": "^[a-zA-Z][a-zA-Z0-9\\-\\s]*$"
12
+ },
13
+ "group": {
14
+ "type": "string",
15
+ "description": "Optional group path (e.g., 'getting-started' or 'advanced/hooks')"
16
+ },
17
+ "engine": {
18
+ "type": "string",
19
+ "description": "Template engine to use",
20
+ "oneOf": [
21
+ { "const": "vanilla-ts", "title": "Vanilla TypeScript" },
22
+ { "const": "vanilla-js", "title": "Vanilla JavaScript" },
23
+ { "const": "react", "title": "React (TSX)" }
24
+ ],
25
+ "default": "vanilla-ts"
26
+ }
27
+ },
28
+ "required": ["name", "engine"]
29
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "<%= playgroundName__humanReadable %>",
3
+ "description": "",
4
+ "dependencies": {
5
+ "react": "^19.0.0",
6
+ "react-dom": "^19.0.0"
7
+ },
8
+ "entry": "index.tsx"
9
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+
3
+ export function App() {
4
+ return <h1>Hello from <%= playgroundName__humanReadable %></h1>;
5
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title><%= playgroundName__humanReadable %></title>
7
+ </head>
8
+ <body>
9
+ <div id="root"></div>
10
+ <script type="module" src="./index.tsx"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import { App } from './App';
4
+
5
+ createRoot(document.getElementById('root')!).render(<App />);
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "<%= playgroundName__humanReadable %>",
3
+ "description": "",
4
+ "dependencies": {},
5
+ "entry": "index.js"
6
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title><%= playgroundName__humanReadable %></title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="./index.js"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,2 @@
1
+ const app = document.getElementById('app');
2
+ app.innerHTML = '<h1>Hello from <%= playgroundName__humanReadable %></h1>';
@@ -0,0 +1,6 @@
1
+ {
2
+ "name": "<%= playgroundName__humanReadable %>",
3
+ "description": "",
4
+ "dependencies": {},
5
+ "entry": "index.ts"
6
+ }
@@ -0,0 +1,12 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title><%= playgroundName__humanReadable %></title>
7
+ </head>
8
+ <body>
9
+ <div id="app"></div>
10
+ <script type="module" src="./index.ts"></script>
11
+ </body>
12
+ </html>
@@ -0,0 +1,2 @@
1
+ const app = document.getElementById('app')!;
2
+ app.innerHTML = '<h1>Hello from <%= playgroundName__humanReadable %></h1>';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Migration: Add getWorkspace() call before getService in runtime files
3
+ *
4
+ * Transforms this._options.getService to this._options.getWorkspace().getService
5
+ * in runtime project files.
6
+ */
7
+ import { Tree } from '@nx/devkit';
8
+ export default function update(tree: Tree): Promise<void>;
9
+ //# sourceMappingURL=add-get-workspace-to-get-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add-get-workspace-to-get-service.d.ts","sourceRoot":"","sources":["../../../src/migrations/4-10-1/add-get-workspace-to-get-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAA6C,MAAM,YAAY,CAAC;AAE7E,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D9D"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Migration: Add getWorkspace() call before getService in runtime files
4
+ *
5
+ * Transforms this._options.getService to this._options.getWorkspace().getService
6
+ * in runtime project files.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.default = update;
10
+ const devkit_1 = require("@nx/devkit");
11
+ async function update(tree) {
12
+ devkit_1.logger.info('🔄 Adding getWorkspace() before getService calls in runtime projects...');
13
+ const runtimesDir = 'unisphere/runtimes';
14
+ if (!tree.exists(runtimesDir)) {
15
+ devkit_1.logger.info('ℹ️ No runtimes directory found');
16
+ return;
17
+ }
18
+ let updatedCount = 0;
19
+ (0, devkit_1.visitNotIgnoredFiles)(tree, runtimesDir, (filePath) => {
20
+ if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx'))
21
+ return;
22
+ const content = tree.read(filePath, 'utf-8');
23
+ if (!content)
24
+ return;
25
+ if (!content.includes('_options') || !content.includes('getService'))
26
+ return;
27
+ // Match this._options followed by optional whitespace/newline/dot then .getService
28
+ // Handles: this._options.getService / this._options.\n .getService / this._options\n .getService
29
+ const pattern = /this\._options\.?\s*\.getService/g;
30
+ if (!pattern.test(content))
31
+ return;
32
+ // Already migrated check: if getWorkspace().getService exists, skip
33
+ if (content.includes('.getWorkspace().getService') || content.includes('.getWorkspace()\n')) {
34
+ // More precise check: see if all occurrences are already migrated
35
+ const unmigrated = content.replace(/this\._options\.getWorkspace\(\)\s*\.getService/g, '');
36
+ if (!/this\._options\.?\s*\.getService/.test(unmigrated)) {
37
+ return;
38
+ }
39
+ }
40
+ const updatedContent = content.replace(/this\._options\.?\s*\.\s*getService/g, 'this._options.getWorkspace().getService');
41
+ if (updatedContent !== content) {
42
+ tree.write(filePath, updatedContent);
43
+ updatedCount++;
44
+ devkit_1.logger.info(` ✅ Updated ${filePath}`);
45
+ }
46
+ });
47
+ if (updatedCount === 0) {
48
+ devkit_1.logger.info('ℹ️ No runtime files needed getWorkspace() insertion before getService');
49
+ }
50
+ else {
51
+ await (0, devkit_1.formatFiles)(tree);
52
+ devkit_1.logger.info(`✅ Updated ${updatedCount} runtime file(s)`);
53
+ }
54
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Migration: Update UnisphereVisualTarget usage
3
+ *
4
+ * 1. Renames `target` property to `type` in visual target object literals
5
+ * (where value is 'body' or 'element')
6
+ * 2. Converts string visual targets to { type: 'element', elementId: '<string>' }
7
+ */
8
+ import { Tree } from '@nx/devkit';
9
+ export default function update(tree: Tree): Promise<void>;
10
+ //# sourceMappingURL=update-unisphere-visual-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update-unisphere-visual-target.d.ts","sourceRoot":"","sources":["../../../src/migrations/4-10-1/update-unisphere-visual-target.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAA6C,MAAM,YAAY,CAAC;AAS7E,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAoF9D"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ /**
3
+ * Migration: Update UnisphereVisualTarget usage
4
+ *
5
+ * 1. Renames `target` property to `type` in visual target object literals
6
+ * (where value is 'body' or 'element')
7
+ * 2. Converts string visual targets to { type: 'element', elementId: '<string>' }
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.default = update;
11
+ const devkit_1 = require("@nx/devkit");
12
+ const ts_morph_1 = require("ts-morph");
13
+ async function update(tree) {
14
+ devkit_1.logger.info('🔄 Updating UnisphereVisualTarget usage...');
15
+ const project = new ts_morph_1.Project({
16
+ manipulationSettings: { quoteKind: ts_morph_1.QuoteKind.Single },
17
+ });
18
+ let updatedCount = 0;
19
+ (0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
20
+ if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx'))
21
+ return;
22
+ if (!filePath.includes('unisphere/'))
23
+ return;
24
+ const content = tree.read(filePath, 'utf-8');
25
+ if (!content)
26
+ return;
27
+ if (!content.includes('target'))
28
+ return;
29
+ const sourceFile = project.createSourceFile(filePath, content, {
30
+ overwrite: true,
31
+ });
32
+ let hasChanges = false;
33
+ // Pass 1: Rename target → type in object literals where value is 'body' or 'element'
34
+ // Only in visual target contexts (mountVisual args, visuals config, nested in target property)
35
+ const allPropertyAssignments = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyAssignment);
36
+ for (const prop of allPropertyAssignments) {
37
+ if (prop.getName() !== 'target')
38
+ continue;
39
+ const initializer = prop.getInitializerIfKind(ts_morph_1.SyntaxKind.StringLiteral);
40
+ if (!initializer)
41
+ continue;
42
+ const value = initializer.getLiteralValue();
43
+ if (value !== 'body' && value !== 'element')
44
+ continue;
45
+ if (!isVisualTargetObjectContext(prop))
46
+ continue;
47
+ prop.getNameNode().replaceWithText('type');
48
+ hasChanges = true;
49
+ }
50
+ // Pass 2: Convert string targets to objects in mountVisual calls and visuals config
51
+ // Re-query after Pass 1 modifications
52
+ const propertyAssignments = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.PropertyAssignment);
53
+ for (const prop of propertyAssignments) {
54
+ if (prop.getName() !== 'target')
55
+ continue;
56
+ const initializer = prop.getInitializerIfKind(ts_morph_1.SyntaxKind.StringLiteral);
57
+ if (!initializer)
58
+ continue;
59
+ const value = initializer.getLiteralValue();
60
+ // Skip 'body' and 'element' - those were handled in Pass 1
61
+ if (value === 'body' || value === 'element')
62
+ continue;
63
+ // Check if this is in a visual target context
64
+ if (!isVisualTargetContext(prop))
65
+ continue;
66
+ // Transform string to { type: 'element', elementId: '<string>' }
67
+ initializer.replaceWithText(`{ type: 'element', elementId: '${value}' }`);
68
+ hasChanges = true;
69
+ }
70
+ if (hasChanges) {
71
+ tree.write(filePath, sourceFile.getFullText());
72
+ updatedCount++;
73
+ devkit_1.logger.info(` ✅ Updated ${filePath}`);
74
+ }
75
+ });
76
+ if (updatedCount === 0) {
77
+ devkit_1.logger.info('ℹ️ No UnisphereVisualTarget usages needed transformation');
78
+ }
79
+ else {
80
+ await (0, devkit_1.formatFiles)(tree);
81
+ devkit_1.logger.info(`✅ Updated UnisphereVisualTarget usage in ${updatedCount} file(s)`);
82
+ }
83
+ }
84
+ /**
85
+ * Checks if a `target` property with value 'body'/'element' is inside a UnisphereVisualTarget object.
86
+ * The object itself (containing target: 'body') is the visual target value, so we check
87
+ * whether it's nested inside a `target` property of a parent, a mountVisual call, or visuals array.
88
+ */
89
+ function isVisualTargetObjectContext(prop) {
90
+ const objLiteral = prop.getParent();
91
+ if (!ts_morph_1.Node.isObjectLiteralExpression(objLiteral))
92
+ return false;
93
+ const objParent = objLiteral.getParent();
94
+ // Context 1: Object is value of a `target` property in a parent object
95
+ // e.g., mountVisual({ target: { target: 'body' } }) — inner object is the visual target
96
+ if (ts_morph_1.Node.isPropertyAssignment(objParent) && objParent.getName() === 'target')
97
+ return true;
98
+ // Context 2: Object is inside a mountVisual() call directly
99
+ // e.g., mountVisual({ target: 'body' }) — less common but possible
100
+ if (ts_morph_1.Node.isCallExpression(objParent)) {
101
+ const expr = objParent.getExpression();
102
+ if (expr.getText().endsWith('mountVisual'))
103
+ return true;
104
+ }
105
+ // Context 3: Object is inside a visuals array item's target property
106
+ // e.g., visuals: [{ target: { target: 'body' } }]
107
+ if (ts_morph_1.Node.isPropertyAssignment(objParent) && objParent.getName() === 'target') {
108
+ const outerObj = objParent.getParent();
109
+ if (ts_morph_1.Node.isObjectLiteralExpression(outerObj)) {
110
+ const arrayParent = outerObj.getParent();
111
+ if (ts_morph_1.Node.isArrayLiteralExpression(arrayParent)) {
112
+ const arrayPropParent = arrayParent.getParent();
113
+ if (ts_morph_1.Node.isPropertyAssignment(arrayPropParent) &&
114
+ arrayPropParent.getName() === 'visuals')
115
+ return true;
116
+ }
117
+ }
118
+ }
119
+ // Context 4: Object has sibling properties that indicate it's a visual target
120
+ // (has elementId for 'element' type, or classNames/style for 'body' type)
121
+ if (objLiteral.getProperty('elementId'))
122
+ return true;
123
+ if (objLiteral.getProperty('classNames'))
124
+ return true;
125
+ if (objLiteral.getProperty('style'))
126
+ return true;
127
+ return false;
128
+ }
129
+ /**
130
+ * Checks if a `target` property with a string value is in a visual target context
131
+ * (the string IS the visual target value, needing conversion to object).
132
+ */
133
+ function isVisualTargetContext(prop) {
134
+ const parent = prop.getParent();
135
+ if (!ts_morph_1.Node.isObjectLiteralExpression(parent))
136
+ return false;
137
+ // Context 1: Inside mountVisual() call argument
138
+ // e.g., super.mountVisual({ type: 'popup', target: 'someId', settings: {} })
139
+ const grandparent = parent.getParent();
140
+ if (ts_morph_1.Node.isCallExpression(grandparent)) {
141
+ const expr = grandparent.getExpression();
142
+ if (expr.getText().endsWith('mountVisual'))
143
+ return true;
144
+ }
145
+ // Context 2: Inside a visuals array item
146
+ // e.g., visuals: [{ target: 'someId', ... }]
147
+ if (ts_morph_1.Node.isArrayLiteralExpression(grandparent)) {
148
+ const arrayParent = grandparent.getParent();
149
+ if (ts_morph_1.Node.isPropertyAssignment(arrayParent)) {
150
+ if (arrayParent.getName() === 'visuals')
151
+ return true;
152
+ }
153
+ }
154
+ // Context 3: Parent object has siblings suggesting visual config
155
+ // (has 'type' property with value like 'popup', 'inline', etc.)
156
+ const typeProp = parent.getProperty('type');
157
+ if (typeProp && ts_morph_1.Node.isPropertyAssignment(typeProp)) {
158
+ const typeInit = typeProp.getInitializerIfKind(ts_morph_1.SyntaxKind.StringLiteral);
159
+ if (typeInit) {
160
+ const typeValue = typeInit.getLiteralValue();
161
+ if (typeValue === 'popup' ||
162
+ typeValue === 'inline' ||
163
+ typeValue === 'drawer')
164
+ return true;
165
+ }
166
+ }
167
+ return false;
168
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Migration: Wrap TinyDataStore/TinyStorage constructor arguments in initialValue
3
+ *
4
+ * Transforms constructor calls to wrap the argument in an { initialValue: ... } object.
5
+ * Skips instances that already have an initialValue property.
6
+ */
7
+ import { Tree } from '@nx/devkit';
8
+ export default function update(tree: Tree): Promise<void>;
9
+ //# sourceMappingURL=wrap-tiny-data-store-initial-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap-tiny-data-store-initial-value.d.ts","sourceRoot":"","sources":["../../../src/migrations/4-10-1/wrap-tiny-data-store-initial-value.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAA6C,MAAM,YAAY,CAAC;AAK7E,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE9D"}
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /**
3
+ * Migration: Wrap TinyDataStore/TinyStorage constructor arguments in initialValue
4
+ *
5
+ * Transforms constructor calls to wrap the argument in an { initialValue: ... } object.
6
+ * Skips instances that already have an initialValue property.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.default = update;
10
+ const devkit_1 = require("@nx/devkit");
11
+ const ts_morph_1 = require("ts-morph");
12
+ const TARGET_CLASSES = ['TinyDataStore', 'TinyStorage'];
13
+ async function update(tree) {
14
+ devkit_1.logger.info('🔄 Wrapping TinyDataStore/TinyStorage constructor arguments in initialValue...');
15
+ const project = new ts_morph_1.Project({
16
+ manipulationSettings: { quoteKind: ts_morph_1.QuoteKind.Single },
17
+ });
18
+ let updatedCount = 0;
19
+ (0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
20
+ if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx'))
21
+ return;
22
+ if (!filePath.includes('unisphere/'))
23
+ return;
24
+ const content = tree.read(filePath, 'utf-8');
25
+ if (!content)
26
+ return;
27
+ if (!TARGET_CLASSES.some((cls) => content.includes(cls)))
28
+ return;
29
+ const sourceFile = project.createSourceFile(filePath, content, {
30
+ overwrite: true,
31
+ });
32
+ let hasChanges = false;
33
+ const newExpressions = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.NewExpression);
34
+ for (const expr of newExpressions) {
35
+ const exprText = expr.getExpression().getText();
36
+ if (!TARGET_CLASSES.includes(exprText))
37
+ continue;
38
+ const args = expr.getArguments();
39
+ if (args.length !== 1)
40
+ continue;
41
+ const arg = args[0];
42
+ // Skip if argument already has an initialValue property
43
+ if (arg.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression) {
44
+ const objLiteral = arg.asKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
45
+ if (objLiteral?.getProperty('initialValue'))
46
+ continue;
47
+ }
48
+ const argText = arg.getText();
49
+ arg.replaceWithText(`{\n initialValue: ${argText},\n }`);
50
+ hasChanges = true;
51
+ }
52
+ if (hasChanges) {
53
+ tree.write(filePath, sourceFile.getFullText());
54
+ updatedCount++;
55
+ devkit_1.logger.info(` ✅ Updated ${filePath}`);
56
+ }
57
+ });
58
+ if (updatedCount === 0) {
59
+ devkit_1.logger.info('ℹ️ No TinyDataStore/TinyStorage instances needed transformation');
60
+ }
61
+ else {
62
+ await (0, devkit_1.formatFiles)(tree);
63
+ devkit_1.logger.info(`✅ Wrapped constructor arguments in initialValue for ${updatedCount} file(s)`);
64
+ }
65
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Migration: Migrate Kava analytics types to Application Events bucket types
3
+ *
4
+ * Renames enums/types and adds the required `bucket: AnalyticsBucket.ApplicationEvents`
5
+ * field to all report() calls.
6
+ */
7
+ import { Tree } from '@nx/devkit';
8
+ export default function update(tree: Tree): Promise<void>;
9
+ //# sourceMappingURL=migrate-analytics-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate-analytics-types.d.ts","sourceRoot":"","sources":["../../../src/migrations/4-11-0/migrate-analytics-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAA6C,MAAM,YAAY,CAAC;AAa7E,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CA2G9D"}
@@ -0,0 +1,102 @@
1
+ "use strict";
2
+ /**
3
+ * Migration: Migrate Kava analytics types to Application Events bucket types
4
+ *
5
+ * Renames enums/types and adds the required `bucket: AnalyticsBucket.ApplicationEvents`
6
+ * field to all report() calls.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.default = update;
10
+ const devkit_1 = require("@nx/devkit");
11
+ const ts_morph_1 = require("ts-morph");
12
+ const RENAMES = {
13
+ KavaEventTypes: 'ApplicationEventTypes',
14
+ KavaButtonsTypes: 'ApplicationButtonTypes',
15
+ KavaPageTypes: 'ApplicationPageTypes',
16
+ KavaBaseTypePayload: 'ApplicationEventsBasePayload',
17
+ KavaButtonTypePayload: 'ApplicationButtonPayload',
18
+ KavaPageTypePayload: 'ApplicationPagePayload',
19
+ KavaRequestPayloadByType: 'AnalyticsPayloadByBucket',
20
+ };
21
+ async function update(tree) {
22
+ devkit_1.logger.info('🔄 Migrating Kava analytics types to Application Events bucket types...');
23
+ const runtimesDir = 'unisphere/runtimes';
24
+ if (!tree.exists(runtimesDir)) {
25
+ devkit_1.logger.info('ℹ️ No runtimes directory found');
26
+ return;
27
+ }
28
+ const project = new ts_morph_1.Project({
29
+ manipulationSettings: { quoteKind: ts_morph_1.QuoteKind.Single },
30
+ });
31
+ let updatedCount = 0;
32
+ (0, devkit_1.visitNotIgnoredFiles)(tree, runtimesDir, (filePath) => {
33
+ if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx'))
34
+ return;
35
+ const content = tree.read(filePath, 'utf-8');
36
+ if (!content)
37
+ return;
38
+ const hasOldTypes = Object.keys(RENAMES).some((old) => content.includes(old));
39
+ if (!hasOldTypes)
40
+ return;
41
+ const sourceFile = project.createSourceFile(filePath, content, {
42
+ overwrite: true,
43
+ });
44
+ let hasChanges = false;
45
+ // Step 1: Add `bucket: AnalyticsBucket.ApplicationEvents` to any object literal
46
+ // containing an `eventType: KavaEventTypes.*` property (covers direct .report() calls
47
+ // and indirect patterns like wrapper functions).
48
+ const objectLiterals = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.ObjectLiteralExpression);
49
+ for (const objLiteral of objectLiterals) {
50
+ if (objLiteral.getProperty('bucket'))
51
+ continue;
52
+ const eventTypeProp = objLiteral.getProperty('eventType');
53
+ if (!eventTypeProp)
54
+ continue;
55
+ const eventTypeText = eventTypeProp.getText();
56
+ if (!eventTypeText.includes('KavaEventTypes.') &&
57
+ !eventTypeText.includes('ApplicationEventTypes.'))
58
+ continue;
59
+ objLiteral.insertPropertyAssignment(0, {
60
+ name: 'bucket',
61
+ initializer: 'AnalyticsBucket.ApplicationEvents',
62
+ });
63
+ hasChanges = true;
64
+ }
65
+ // Step 2: Rename all old type/enum references
66
+ let updatedText = sourceFile.getFullText();
67
+ for (const [oldName, newName] of Object.entries(RENAMES)) {
68
+ const regex = new RegExp(`\\b${oldName}\\b`, 'g');
69
+ if (regex.test(updatedText)) {
70
+ updatedText = updatedText.replace(regex, newName);
71
+ hasChanges = true;
72
+ }
73
+ }
74
+ // Step 3: Add AnalyticsBucket to imports from @unisphere/runtime
75
+ if (hasChanges) {
76
+ if (updatedText.includes('AnalyticsBucket') &&
77
+ !updatedText.match(/import\s*\{[^}]*AnalyticsBucket[^}]*\}\s*from\s*['"]@unisphere\/runtime['"]/)) {
78
+ updatedText = updatedText.replace(/(import\s*\{)([^}]*)(}\s*from\s*['"]@unisphere\/runtime['"])/, (_match, start, imports, end) => {
79
+ const importList = imports
80
+ .split(',')
81
+ .map((s) => s.trim())
82
+ .filter(Boolean);
83
+ if (!importList.includes('AnalyticsBucket')) {
84
+ importList.push('AnalyticsBucket');
85
+ importList.sort();
86
+ }
87
+ return `${start}\n ${importList.join(',\n ')},\n${end}`;
88
+ });
89
+ }
90
+ tree.write(filePath, updatedText);
91
+ updatedCount++;
92
+ devkit_1.logger.info(` ✅ Updated ${filePath}`);
93
+ }
94
+ });
95
+ if (updatedCount === 0) {
96
+ devkit_1.logger.info('ℹ️ No files needed analytics type migration');
97
+ }
98
+ else {
99
+ await (0, devkit_1.formatFiles)(tree);
100
+ devkit_1.logger.info(`✅ Migrated analytics types in ${updatedCount} file(s)`);
101
+ }
102
+ }
@@ -0,0 +1,3 @@
1
+ import { Tree } from '@nx/devkit';
2
+ export default function update(tree: Tree): Promise<void>;
3
+ //# sourceMappingURL=restore-security-audit-step.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restore-security-audit-step.d.ts","sourceRoot":"","sources":["../../../src/migrations/4-8-0/restore-security-audit-step.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAU,MAAM,YAAY,CAAC;AAO1C,wBAA8B,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAiD9D"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = update;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const AUDIT_STEP = ` - name: Security Audit
6
+ run: npx unisphere tools audit
7
+ env:
8
+ KALTURA_JFROG_TOKEN: \${{ steps.setup-jfrog.outputs.oidc-token }}`;
9
+ async function update(tree) {
10
+ const cicdPath = '.github/workflows/cicd.yml';
11
+ if (!tree.exists(cicdPath)) {
12
+ devkit_1.logger.warn('⚠️ No cicd.yml found, skipping');
13
+ return;
14
+ }
15
+ let content = tree.read(cicdPath, 'utf-8');
16
+ if (!content) {
17
+ devkit_1.logger.warn('⚠️ Could not read cicd.yml, skipping');
18
+ return;
19
+ }
20
+ const commentedPattern = /^[ \t]*#\s*- name: Security Audit\s*\n(?:[ \t]*#.*\n)*/m;
21
+ if (commentedPattern.test(content)) {
22
+ content = content.replace(commentedPattern, AUDIT_STEP + '\n');
23
+ tree.write(cicdPath, content);
24
+ devkit_1.logger.info('✅ Uncommented Security Audit step in cicd.yml');
25
+ return;
26
+ }
27
+ if (content.includes('Security Audit')) {
28
+ devkit_1.logger.info('ℹ️ Security Audit step already exists in cicd.yml');
29
+ return;
30
+ }
31
+ const installDepsMatch = content.match(/( *- name: Install Dependencies[ \t]*\n(?:.*\n)*?)([ \t]*- name: )/);
32
+ if (!installDepsMatch) {
33
+ devkit_1.logger.warn('⚠️ Could not find Install Dependencies step in cicd.yml');
34
+ throw new Error('Could not find Install Dependencies step in cicd.yml');
35
+ }
36
+ const insertIndex = installDepsMatch.index + installDepsMatch[1].length;
37
+ content =
38
+ content.slice(0, insertIndex) +
39
+ '\n' +
40
+ AUDIT_STEP +
41
+ '\n\n' +
42
+ content.slice(insertIndex);
43
+ tree.write(cicdPath, content);
44
+ devkit_1.logger.info('✅ Added Security Audit step to cicd.yml');
45
+ }
package/generators.json CHANGED
@@ -55,6 +55,11 @@
55
55
  "factory": "./dist/generators/internal-dev-runner/generator",
56
56
  "schema": "./dist/generators/internal-dev-runner/schema.json",
57
57
  "description": "Internal-dev-runner - Run a migration for testing purposes (dev only)"
58
+ },
59
+ "add-playground": {
60
+ "factory": "./dist/generators/add-playground/add-playground",
61
+ "schema": "./dist/generators/add-playground/schema.json",
62
+ "description": "Add a code playground example"
58
63
  }
59
64
  }
60
65
  }
package/migrations.json CHANGED
@@ -450,6 +450,46 @@
450
450
  "cli": {
451
451
  "postUpdateMessage": "✅ GitHub documentation workflow added"
452
452
  }
453
+ },
454
+ "4-8-0-restore-security-audit-step": {
455
+ "version": "4.8.0",
456
+ "description": "Restores Security Audit step in cicd.yml if commented out or missing",
457
+ "factory": "./dist/migrations/4-8-0/restore-security-audit-step.js",
458
+ "cli": {
459
+ "postUpdateMessage": "✅ Security Audit step restored in cicd.yml"
460
+ }
461
+ },
462
+ "4-10-1-wrap-tiny-data-store-initial-value": {
463
+ "version": "4.10.1",
464
+ "description": "Wraps TinyDataStore/TinyStorage constructor arguments in initialValue property",
465
+ "factory": "./dist/migrations/4-10-1/wrap-tiny-data-store-initial-value.js",
466
+ "cli": {
467
+ "postUpdateMessage": "✅ TinyDataStore/TinyStorage constructor arguments wrapped in initialValue"
468
+ }
469
+ },
470
+ "4-10-1-add-get-workspace-to-get-service": {
471
+ "version": "4.10.1",
472
+ "description": "Adds getWorkspace() call before getService in runtime files",
473
+ "factory": "./dist/migrations/4-10-1/add-get-workspace-to-get-service.js",
474
+ "cli": {
475
+ "postUpdateMessage": "✅ Runtime files updated: this._options.getService → this._options.getWorkspace().getService"
476
+ }
477
+ },
478
+ "4-10-1-update-unisphere-visual-target": {
479
+ "version": "4.10.1",
480
+ "description": "Updates UnisphereVisualTarget usage: renames target→type, converts string targets to objects",
481
+ "factory": "./dist/migrations/4-10-1/update-unisphere-visual-target.js",
482
+ "cli": {
483
+ "postUpdateMessage": "✅ UnisphereVisualTarget usage updated (target→type, string→object)"
484
+ }
485
+ },
486
+ "4-11-0-migrate-analytics-types": {
487
+ "version": "4.11.0",
488
+ "description": "Migrates Kava analytics types to Application Events bucket types (KavaEventTypes→ApplicationEventTypes, KavaButtonsTypes→ApplicationButtonTypes, adds bucket field)",
489
+ "factory": "./dist/migrations/4-11-0/migrate-analytics-types.js",
490
+ "cli": {
491
+ "postUpdateMessage": "✅ Analytics types migrated to Application Events bucket pattern"
492
+ }
453
493
  }
454
494
  },
455
495
  "packageJsonUpdates": {
@@ -772,6 +812,40 @@
772
812
  "alwaysAddToPackageJson": false
773
813
  }
774
814
  }
815
+ },
816
+ "4.8.0": {
817
+ "version": "4.8.0",
818
+ "cli": "nx",
819
+ "postUpdateMessage": "🎉 Migration to @unisphere/nx 4.8.0 completed successfully!",
820
+ "packages": {
821
+ "@unisphere/cli": {
822
+ "version": "5.2.0",
823
+ "alwaysAddToPackageJson": false
824
+ }
825
+ }
826
+ },
827
+ "4.10.1": {
828
+ "version": "4.10.1",
829
+ "cli": "nx",
830
+ "postUpdateMessage": "🎉 Migration to @unisphere/nx 4.10.1 completed successfully!",
831
+ "packages": {
832
+ "@unisphere/core": {
833
+ "version": "^1.97.1",
834
+ "alwaysAddToPackageJson": false
835
+ },
836
+ "@unisphere/runtime": {
837
+ "version": "^1.97.0",
838
+ "alwaysAddToPackageJson": false
839
+ },
840
+ "@unisphere/runtime-js": {
841
+ "version": "^1.93.0",
842
+ "alwaysAddToPackageJson": false
843
+ },
844
+ "@unisphere/runtime-react": {
845
+ "version": "^1.87.0",
846
+ "alwaysAddToPackageJson": false
847
+ }
848
+ }
775
849
  }
776
850
  }
777
851
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unisphere/nx",
3
- "version": "4.7.0",
3
+ "version": "4.10.1",
4
4
  "private": false,
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",