@unisphere/nx 1.0.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 (102) hide show
  1. package/README.md +32 -0
  2. package/dist/generators/add-application/add-application.d.ts +5 -0
  3. package/dist/generators/add-application/add-application.d.ts.map +1 -0
  4. package/dist/generators/add-application/add-application.js +98 -0
  5. package/dist/generators/add-application/schema.d.ts +6 -0
  6. package/dist/generators/add-application/schema.json +92 -0
  7. package/dist/generators/add-application/templates/default/.babelrc +11 -0
  8. package/dist/generators/add-application/templates/default/.eslintrc.json +18 -0
  9. package/dist/generators/add-application/templates/default/jest.config.d.ts +14 -0
  10. package/dist/generators/add-application/templates/default/jest.config.d.ts.map +1 -0
  11. package/dist/generators/add-application/templates/default/jest.config.js +13 -0
  12. package/dist/generators/add-application/templates/default/package.json.template +7 -0
  13. package/dist/generators/add-application/templates/default/project.json.template +9 -0
  14. package/dist/generators/add-application/templates/default/src/app/app.tsx.template +76 -0
  15. package/dist/generators/add-application/templates/default/src/favicon.ico +0 -0
  16. package/dist/generators/add-application/templates/default/src/index.html.template +17 -0
  17. package/dist/generators/add-application/templates/default/src/main.tsx +13 -0
  18. package/dist/generators/add-application/templates/default/src/styles.css +0 -0
  19. package/dist/generators/add-application/templates/default/tsconfig.app.json +24 -0
  20. package/dist/generators/add-application/templates/default/tsconfig.json +20 -0
  21. package/dist/generators/add-application/templates/default/tsconfig.spec.json +25 -0
  22. package/dist/generators/add-application/templates/default/webpack.config.js.template +33 -0
  23. package/dist/generators/add-application/templates/interactive-playground/.babelrc +11 -0
  24. package/dist/generators/add-application/templates/interactive-playground/.eslintrc.json +18 -0
  25. package/dist/generators/add-application/templates/interactive-playground/jest.config.d.ts +14 -0
  26. package/dist/generators/add-application/templates/interactive-playground/jest.config.d.ts.map +1 -0
  27. package/dist/generators/add-application/templates/interactive-playground/jest.config.js +13 -0
  28. package/dist/generators/add-application/templates/interactive-playground/package.json +7 -0
  29. package/dist/generators/add-application/templates/interactive-playground/project.json +9 -0
  30. package/dist/generators/add-application/templates/interactive-playground/src/app/app.tsx.template +122 -0
  31. package/dist/generators/add-application/templates/interactive-playground/src/app/components/header.tsx.template +123 -0
  32. package/dist/generators/add-application/templates/interactive-playground/src/app/components/settings-buttons.tsx +59 -0
  33. package/dist/generators/add-application/templates/interactive-playground/src/app/components/settings-form.tsx +104 -0
  34. package/dist/generators/add-application/templates/interactive-playground/src/app/components/settings.tsx +74 -0
  35. package/dist/generators/add-application/templates/interactive-playground/src/app/configuration-provider.tsx +163 -0
  36. package/dist/generators/add-application/templates/interactive-playground/src/app/definitions.d.ts +11 -0
  37. package/dist/generators/add-application/templates/interactive-playground/src/app/definitions.d.ts.map +1 -0
  38. package/dist/generators/add-application/templates/interactive-playground/src/app/definitions.js +19 -0
  39. package/dist/generators/add-application/templates/interactive-playground/src/app/utils/merge-deep.d.ts +13 -0
  40. package/dist/generators/add-application/templates/interactive-playground/src/app/utils/merge-deep.d.ts.map +1 -0
  41. package/dist/generators/add-application/templates/interactive-playground/src/app/utils/merge-deep.js +35 -0
  42. package/dist/generators/add-application/templates/interactive-playground/src/favicon.ico +0 -0
  43. package/dist/generators/add-application/templates/interactive-playground/src/index.html +17 -0
  44. package/dist/generators/add-application/templates/interactive-playground/src/main.tsx +13 -0
  45. package/dist/generators/add-application/templates/interactive-playground/src/styles.css +0 -0
  46. package/dist/generators/add-application/templates/interactive-playground/tsconfig.app.json +24 -0
  47. package/dist/generators/add-application/templates/interactive-playground/tsconfig.json +20 -0
  48. package/dist/generators/add-application/templates/interactive-playground/tsconfig.spec.json +25 -0
  49. package/dist/generators/add-application/templates/interactive-playground/webpack.config.js +33 -0
  50. package/dist/generators/add-package/README.md +70 -0
  51. package/dist/generators/add-package/add-package.d.ts +5 -0
  52. package/dist/generators/add-package/add-package.d.ts.map +1 -0
  53. package/dist/generators/add-package/add-package.js +85 -0
  54. package/dist/generators/add-package/files/.babelrc +12 -0
  55. package/dist/generators/add-package/files/.eslintrc.json +18 -0
  56. package/dist/generators/add-package/files/README.md +1 -0
  57. package/dist/generators/add-package/files/package.json.template +22 -0
  58. package/dist/generators/add-package/files/project.json.template +22 -0
  59. package/dist/generators/add-package/files/rollup.config.js +6 -0
  60. package/dist/generators/add-package/files/src/index.ts +1 -0
  61. package/dist/generators/add-package/files/tsconfig.json +20 -0
  62. package/dist/generators/add-package/files/tsconfig.lib.json +23 -0
  63. package/dist/generators/add-package/files/tsconfig.spec.json +26 -0
  64. package/dist/generators/add-package/files/vite.config.ts +30 -0
  65. package/dist/generators/add-package/schema.d.ts +4 -0
  66. package/dist/generators/add-package/schema.json +46 -0
  67. package/dist/generators/add-runtime/add-runtime.d.ts +5 -0
  68. package/dist/generators/add-runtime/add-runtime.d.ts.map +1 -0
  69. package/dist/generators/add-runtime/add-runtime.js +112 -0
  70. package/dist/generators/add-runtime/core-templates/__runtimeName__-runtime/runtime-types.ts.template +21 -0
  71. package/dist/generators/add-runtime/files/.babelrc +12 -0
  72. package/dist/generators/add-runtime/files/.eslintrc.json +18 -0
  73. package/dist/generators/add-runtime/files/README.md.template +1 -0
  74. package/dist/generators/add-runtime/files/package.json.template +12 -0
  75. package/dist/generators/add-runtime/files/project.json.template +22 -0
  76. package/dist/generators/add-runtime/files/rollup.config.js +6 -0
  77. package/dist/generators/add-runtime/files/src/index.ts +1 -0
  78. package/dist/generators/add-runtime/files/src/lib/create-factory.tsx.template +21 -0
  79. package/dist/generators/add-runtime/files/src/lib/runtime.tsx.template +66 -0
  80. package/dist/generators/add-runtime/files/tsconfig.json +20 -0
  81. package/dist/generators/add-runtime/files/tsconfig.lib.json +23 -0
  82. package/dist/generators/add-runtime/files/tsconfig.spec.json +26 -0
  83. package/dist/generators/add-runtime/files/vite.config.ts +30 -0
  84. package/dist/generators/add-runtime/schema.d.ts +4 -0
  85. package/dist/generators/add-runtime/schema.json +44 -0
  86. package/dist/generators/add-visual/add-visual.d.ts +8 -0
  87. package/dist/generators/add-visual/add-visual.d.ts.map +1 -0
  88. package/dist/generators/add-visual/add-visual.js +236 -0
  89. package/dist/generators/add-visual/files/render-method.template +31 -0
  90. package/dist/generators/add-visual/schema.d.ts +5 -0
  91. package/dist/generators/add-visual/schema.json +30 -0
  92. package/dist/generators/add-visual/visual-utils.d.ts +42 -0
  93. package/dist/generators/add-visual/visual-utils.d.ts.map +1 -0
  94. package/dist/generators/add-visual/visual-utils.js +99 -0
  95. package/dist/generators/utils.d.ts +18 -0
  96. package/dist/generators/utils.d.ts.map +1 -0
  97. package/dist/generators/utils.js +198 -0
  98. package/dist/index.d.ts +2 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +2 -0
  101. package/generators.json +24 -0
  102. package/package.json +81 -0
@@ -0,0 +1,236 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addVisualGenerator = addVisualGenerator;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const path = tslib_1.__importStar(require("path"));
7
+ const ts_morph_1 = require("ts-morph");
8
+ const utils_1 = require("../utils");
9
+ const visual_utils_1 = require("./visual-utils");
10
+ /**
11
+ * Adds necessary imports (runtimeVisualSettings, runtimeVisualSchema) to the runtime file.
12
+ */
13
+ function addImportToRuntime(sourceFilePath, tree, vars, project) {
14
+ const sourceFile = (0, visual_utils_1.loadSourceFile)(tree, sourceFilePath, project);
15
+ const { visualName__humanReadable: humanName, runtimeVisualSettings, runtimeVisualSchema, coreAlias, } = vars;
16
+ // Check if import already exists to prevent duplicates
17
+ const alreadyExists = sourceFile
18
+ .getImportDeclarations()
19
+ .some((decl) => decl
20
+ .getNamedImports()
21
+ .some((imp) => imp.getName() === runtimeVisualSettings));
22
+ if (alreadyExists) {
23
+ console.log(`⚠️ Import for visual ${humanName} already exists.`);
24
+ return;
25
+ }
26
+ sourceFile.addImportDeclaration({
27
+ kind: ts_morph_1.StructureKind.ImportDeclaration,
28
+ namedImports: [runtimeVisualSettings, runtimeVisualSchema],
29
+ moduleSpecifier: coreAlias,
30
+ }); // Explicit cast for clarity
31
+ (0, visual_utils_1.saveSourceFile)(tree, sourceFilePath, sourceFile.getFullText());
32
+ console.log(`✅ Added import for visual ${humanName}`);
33
+ }
34
+ /**
35
+ * Adds a new case to the primary switch statement in the runtime file.
36
+ */
37
+ function addSwitchCaseToRuntime(sourceFilePath, tree, vars, project) {
38
+ const sourceFile = (0, visual_utils_1.loadSourceFile)(tree, sourceFilePath, project);
39
+ const { visualName__camelCase: visualCamel, visualName__pascalCase: visualPascal, visualName__humanReadable: humanName, } = vars;
40
+ const switchStatement = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.SwitchStatement)[0];
41
+ (0, visual_utils_1.throwIfNotFound)(switchStatement, `No switch statement found in ${sourceFilePath}`);
42
+ const caseBlock = switchStatement.getCaseBlock();
43
+ const cases = caseBlock.getClauses();
44
+ const exists = cases.some((c) => {
45
+ if (c.getKind() === ts_morph_1.SyntaxKind.CaseClause) {
46
+ const clause = c;
47
+ return (clause.getExpression()?.getText().replace(/['"]/g, '') === visualCamel);
48
+ }
49
+ return false;
50
+ });
51
+ if (exists) {
52
+ console.log(`⚠️ Switch case for visual ${humanName} already exists.`);
53
+ return;
54
+ }
55
+ const newCase = `case '${visualCamel}':
56
+ this._render${visualPascal}(visual);
57
+ return true`;
58
+ const defaultIndex = cases.findIndex((c) => c.getKind() === ts_morph_1.SyntaxKind.DefaultClause);
59
+ if (defaultIndex !== -1) {
60
+ const defaultClause = cases[defaultIndex];
61
+ defaultClause.replaceWithText(`${newCase}\n${defaultClause.getText()}`);
62
+ }
63
+ else {
64
+ const lastCase = cases[cases.length - 1];
65
+ lastCase.replaceWithText(`${lastCase.getText()}\n${newCase}`);
66
+ }
67
+ (0, visual_utils_1.saveSourceFile)(tree, sourceFilePath, sourceFile.getFullText());
68
+ console.log(`✅ Added switch case for visual ${humanName}`);
69
+ }
70
+ /**
71
+ * Adds a new visual type entry to the `visualTypes` object within the constructor's super call.
72
+ */
73
+ function addVisualTypesToConstructor(sourceFilePath, tree, vars, project, isSingleOccurrence) {
74
+ const sourceFile = (0, visual_utils_1.loadSourceFile)(tree, sourceFilePath, project);
75
+ const { visualName__camelCase: visualCamel, visualName__humanReadable: humanName, runtimeVisualSchema, } = vars;
76
+ const clazz = (0, visual_utils_1.findFirstClass)(sourceFile);
77
+ const constructor = (0, visual_utils_1.findFirstConstructor)(clazz);
78
+ const superCall = (0, visual_utils_1.findSuperCall)(constructor);
79
+ const objectLiteral = (0, visual_utils_1.getObjectLiteralFromFirstArg)(superCall);
80
+ const visualTypesProp = (0, visual_utils_1.throwIfNotFound)(objectLiteral
81
+ .getProperties()
82
+ .find((prop) => prop.getKind() === ts_morph_1.SyntaxKind.PropertyAssignment &&
83
+ prop.getName() === 'visualTypes'), // Assert type after finding
84
+ `Could not find visualTypes property in super() call in ${sourceFilePath}`);
85
+ const visualTypesObject = (0, visual_utils_1.throwIfNotFound)(visualTypesProp.getInitializer(), // Assert type after getting initializer
86
+ `visualTypes is not an object literal in ${sourceFilePath}`);
87
+ if ((0, visual_utils_1.propertyExists)(visualTypesObject, visualCamel)) {
88
+ console.log(`⚠️ Visual type for visual ${humanName} already exists.`);
89
+ return;
90
+ }
91
+ visualTypesObject.addPropertyAssignment({
92
+ name: `'${visualCamel}'`, // Ensure the key is consistently quoted for string literals
93
+ initializer: `{ singleton: ${isSingleOccurrence}, schema: ${runtimeVisualSchema} }`,
94
+ });
95
+ (0, visual_utils_1.saveSourceFile)(tree, sourceFilePath, sourceFile.getFullText());
96
+ console.log(`✅ Added visual type for ${humanName} to visualTypes.`);
97
+ }
98
+ /**
99
+ * Adds a private render method to the main class in the runtime file.
100
+ * Uses Nx's generateFiles for proper template processing.
101
+ */
102
+ function addRenderMethod(sourceFilePath, tree, vars, project) {
103
+ const sourceFile = (0, visual_utils_1.loadSourceFile)(tree, sourceFilePath, project);
104
+ const methodName = `_render${vars.visualName__pascalCase}`;
105
+ const clazz = (0, visual_utils_1.findFirstClass)(sourceFile);
106
+ // Check if method already exists.
107
+ const exists = clazz
108
+ .getInstanceMethods()
109
+ .some((m) => m.getName() === methodName);
110
+ if (exists) {
111
+ console.log(`⚠️ Method ${methodName} already exists.`);
112
+ return;
113
+ }
114
+ // Use Nx's generateFiles to process the template to a temporary location
115
+ const tempDir = 'temp-render-method';
116
+ (0, devkit_1.generateFiles)(tree, path.join(__dirname, 'files'), tempDir, {
117
+ ...vars,
118
+ tmpl: '', // This removes the .template extension
119
+ });
120
+ // Read the processed template content
121
+ const processedContent = (0, visual_utils_1.readTreeFile)(tree, `${tempDir}/render-method`);
122
+ // Clean up the temporary file
123
+ tree.delete(`${tempDir}/render-method`);
124
+ // Add the private method to the class using ts-morph's addMethod
125
+ clazz.addMethod({
126
+ name: methodName,
127
+ parameters: [{ name: 'visual', type: 'HtmlDomRuntimeVisual<Root>' }],
128
+ statements: processedContent,
129
+ scope: ts_morph_1.Scope.Private,
130
+ });
131
+ // Check if ThemeProvider import exists, add if missing
132
+ const themeProviderImportExists = sourceFile
133
+ .getImportDeclarations()
134
+ .some((decl) => decl.getModuleSpecifier().getLiteralValue() ===
135
+ '@kaltura/ds-react-theme' &&
136
+ decl.getNamedImports().some((imp) => imp.getName() === 'ThemeProvider'));
137
+ if (!themeProviderImportExists) {
138
+ sourceFile.addImportDeclaration({
139
+ kind: ts_morph_1.StructureKind.ImportDeclaration,
140
+ namedImports: ['ThemeProvider'],
141
+ moduleSpecifier: '@kaltura/ds-react-theme',
142
+ });
143
+ console.log(`✅ Added ThemeProvider import to ${sourceFilePath}`);
144
+ }
145
+ (0, visual_utils_1.saveSourceFile)(tree, sourceFilePath, sourceFile.getFullText());
146
+ console.log(`✅ Added render method ${methodName}.`);
147
+ }
148
+ /**
149
+ * Adds an interface and schema definition to the core runtime types file.
150
+ */
151
+ function addVariablesInCore(tree, vars) {
152
+ const coreFile = `unisphere/packages/core/src/lib/${vars.runtimeName__lowerDashCase}-runtime/runtime-types.ts`;
153
+ if (!tree.exists(coreFile)) {
154
+ throw new Error(`Core file not found at ${coreFile}`);
155
+ }
156
+ const currentContent = (0, visual_utils_1.readTreeFile)(tree, coreFile);
157
+ const { runtimeVisualSettings: interfaceName, runtimeVisualSchema: schemaName, visualName__humanReadable: humanName, } = vars;
158
+ // Check if the interface already exists to prevent duplicates.
159
+ if (currentContent.includes(`export interface ${interfaceName}`)) {
160
+ console.log(`⚠️ Interface ${interfaceName} already exists in core file.`);
161
+ return;
162
+ }
163
+ // Construct the new interface and schema content.
164
+ const newContent = `
165
+ export interface ${interfaceName} {
166
+ schemaVersion?: string;
167
+ }
168
+
169
+ export const ${schemaName}: ValidatorSchema = {
170
+ type: 'object',
171
+ properties: {
172
+ schemaVersion: { type: 'literal', value: '1', optional: true },
173
+ },
174
+ };
175
+ `;
176
+ // Append the new content to the file.
177
+ tree.write(coreFile, currentContent + newContent);
178
+ console.log(`✅ Added interface and schema for ${humanName} to core file.`);
179
+ }
180
+ /* -------------------------------------------
181
+ * Entry Point (Main generator function)
182
+ * -----------------------------------------*/
183
+ /**
184
+ * Nx generator to create a new visual within a specified runtime.
185
+ */
186
+ async function addVisualGenerator(tree, options) {
187
+ const { runtimeName, visualName, isSingleOccurrence } = options;
188
+ const unisphereConfig = (0, utils_1.validateUnisphereConfig)(tree);
189
+ // Extract environment variables
190
+ const widgetName = unisphereConfig.name;
191
+ // Validate runtime existence and get source root path.
192
+ const runtimeSourceRoot = (0, utils_1.validateRuntimeExists)(tree, runtimeName);
193
+ const runtimeTSxPath = `${runtimeSourceRoot}/src/lib/runtime.tsx`;
194
+ // Get core package alias and compute various name transforms.
195
+ const coreAlias = (0, utils_1.findCorePackageAlias)(tree);
196
+ const runtimeNames = (0, utils_1.createNameTransforms)(runtimeName, 'runtimeName');
197
+ const visualNames = (0, utils_1.createNameTransforms)(visualName, 'visualName');
198
+ const widgetNames = (0, utils_1.createNameTransforms)(widgetName, 'widgetName');
199
+ // Derive specific names for runtime visual settings and schema based on transforms.
200
+ const runtimeVisualSettings = `${runtimeNames.runtimeName__pascalCase}Runtime${visualNames.visualName__pascalCase}VisualSettings`;
201
+ const runtimeVisualSchema = `${runtimeNames.runtimeName__camelCase}Runtime${visualNames.visualName__pascalCase}VisualSettingsSchema`;
202
+ // Combine all template variables for easy access and passing to functions.
203
+ const templateVariables = {
204
+ ...runtimeNames,
205
+ ...visualNames,
206
+ ...widgetNames,
207
+ runtimeVisualSettings,
208
+ runtimeVisualSchema,
209
+ coreAlias,
210
+ };
211
+ // Ensure the target runtime file exists before proceeding.
212
+ if (!tree.exists(runtimeTSxPath)) {
213
+ throw new Error(`Runtime file not found at ${runtimeTSxPath}`);
214
+ }
215
+ // Initialize ts-morph project with an in-memory file system for modifications.
216
+ const project = new ts_morph_1.Project({
217
+ useInMemoryFileSystem: true,
218
+ skipAddingFilesFromTsConfig: true,
219
+ });
220
+ // Execute all code modification steps.
221
+ addImportToRuntime(runtimeTSxPath, tree, templateVariables, project);
222
+ addVisualTypesToConstructor(runtimeTSxPath, tree, templateVariables, project, isSingleOccurrence);
223
+ addSwitchCaseToRuntime(runtimeTSxPath, tree, templateVariables, project);
224
+ addRenderMethod(runtimeTSxPath, tree, templateVariables, project);
225
+ // 'project' parameter is not needed here as addVariablesInCore directly writes to the tree.
226
+ addVariablesInCore(tree, templateVariables);
227
+ // Format all modified files for consistent code style.
228
+ await (0, devkit_1.formatFiles)(tree);
229
+ // Log success and summary information to the console.
230
+ console.log(`\n🎉 Successfully added visual '${visualName}' to runtime '${runtimeName}'!`);
231
+ console.log(` Runtime: ${runtimeName} (${runtimeSourceRoot})`);
232
+ console.log(` Visual: ${visualName}`);
233
+ console.log(` Single occurrence: ${isSingleOccurrence ? 'Yes' : 'No'}`);
234
+ console.log(` Modified file: ${runtimeTSxPath}`);
235
+ }
236
+ exports.default = addVisualGenerator;
@@ -0,0 +1,31 @@
1
+ if (!this._theme) {
2
+ this._logger.log('cannot render <%= visualName__humanReadable %> - theme not available');
3
+ return;
4
+ }
5
+
6
+ // It is safe to assume the settings type here as it was already validated by the base class
7
+ const visualSettings: <%= runtimeName__pascalCase %>Runtime<%= visualName__pascalCase %>VisualSettings = visual.settings as unknown as <%= runtimeName__pascalCase %>Runtime<%= visualName__pascalCase %>VisualSettings;
8
+
9
+ this._logger.log('rendering <%= visualName__humanReadable %>');
10
+
11
+ visual.htmlContainer?.render(
12
+ <ScopedUnisphereWorkspaceProvider unisphereWorkspace={this._workspace}>
13
+ <ThemeProvider
14
+ cssPrefix={'<%= widgetName__lowerDashCase %>-<%= runtimeName__lowerDashCase %>-<%= visualName__lowerDashCase %>'}
15
+ mode={typeof this._theme === 'string' ? this._theme : this._theme.mode}
16
+ overrides={typeof this._theme === 'string' ? undefined : this._theme}
17
+ style={{
18
+ width: '100%',
19
+ display: 'flex',
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ overflow: 'hidden',
23
+ }}
24
+ className={'unisphere-<%= widgetName__lowerDashCase %>-<%= runtimeName__lowerDashCase %>'}
25
+ >
26
+ <div>
27
+ {/* TODO: Add your <%= visualName__humanReadable %> implementation here */}
28
+ </div>
29
+ </ThemeProvider>
30
+ </ScopedUnisphereWorkspaceProvider>
31
+ );
@@ -0,0 +1,5 @@
1
+ export interface AddVisualGeneratorSchema {
2
+ runtimeName: string;
3
+ visualName: string;
4
+ isSingleOccurrence: boolean;
5
+ }
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "AddVisual",
4
+ "title": "Add Visual Generator",
5
+ "type": "object",
6
+ "properties": {
7
+ "runtimeName": {
8
+ "type": "string",
9
+ "description": "Name of the runtime",
10
+ "x-prompt": "What is the runtime name?"
11
+ },
12
+ "visualName": {
13
+ "type": "string",
14
+ "description": "Name of the visual",
15
+ "x-prompt": "What is the visual name?"
16
+ },
17
+ "isSingleOccurrence": {
18
+ "type": "boolean",
19
+ "description": "Is this visual limited to single occurrence?",
20
+ "x-prompt": {
21
+ "message": "Is this visual limited to single occurrence?",
22
+ "type": "confirmation"
23
+ }
24
+ }
25
+ },
26
+ "required": [
27
+ "runtimeName",
28
+ "isSingleOccurrence"
29
+ ]
30
+ }
@@ -0,0 +1,42 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { CallExpression, ClassDeclaration, ConstructorDeclaration, ObjectLiteralExpression, Project, SourceFile } from 'ts-morph';
3
+ /**
4
+ * Reads the content of a file from the Nx Tree.
5
+ * Throws an error if the file cannot be read.
6
+ */
7
+ export declare function readTreeFile(tree: Tree, filePath: string): string;
8
+ /**
9
+ * Loads a file from the Nx Tree into a ts-morph Project.
10
+ * Uses `readTreeFile` to get content.
11
+ */
12
+ export declare function loadSourceFile(tree: Tree, filePath: string, project: Project): SourceFile;
13
+ /**
14
+ * Saves the updated source file content back to the Nx Tree.
15
+ */
16
+ export declare function saveSourceFile(tree: Tree, filePath: string, sourceFileContent: string): void;
17
+ /**
18
+ * Throws an error if the provided item is null or undefined.
19
+ * Returns the item with a non-null/undefined type assertion.
20
+ */
21
+ export declare function throwIfNotFound<T>(item: T | null | undefined, message: string): T;
22
+ /**
23
+ * Checks if a property exists in an ObjectLiteralExpression, handling quoted keys.
24
+ */
25
+ export declare function propertyExists(objectLiteral: ObjectLiteralExpression, propName: string): boolean;
26
+ /**
27
+ * Finds the first ClassDeclaration in a SourceFile.
28
+ */
29
+ export declare function findFirstClass(sourceFile: SourceFile): ClassDeclaration;
30
+ /**
31
+ * Finds the first ConstructorDeclaration in a ClassDeclaration.
32
+ */
33
+ export declare function findFirstConstructor(clazz: ClassDeclaration): ConstructorDeclaration;
34
+ /**
35
+ * Finds the `super()` CallExpression within a ConstructorDeclaration.
36
+ */
37
+ export declare function findSuperCall(constructor: ConstructorDeclaration): CallExpression;
38
+ /**
39
+ * Gets the first argument of a CallExpression, asserting it's an ObjectLiteralExpression.
40
+ */
41
+ export declare function getObjectLiteralFromFirstArg(callExpression: CallExpression): ObjectLiteralExpression;
42
+ //# sourceMappingURL=visual-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-utils.d.ts","sourceRoot":"","sources":["../../../src/generators/add-visual/visual-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EACH,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACvB,OAAO,EAEP,UAAU,EAEb,MAAM,UAAU,CAAC;AAOlB;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,UAAU,CAGZ;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,iBAAiB,EAAE,MAAM,GACxB,IAAI,CAGN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,CAAC,CAKjF;AAID;;GAEG;AACH,wBAAgB,cAAc,CAC5B,aAAa,EAAE,uBAAuB,EACtC,QAAQ,EAAE,MAAM,GACf,OAAO,CAUT;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,CAMvE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,gBAAgB,GAAG,sBAAsB,CAMpF;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,WAAW,EAAE,sBAAsB,GAAG,cAAc,CAQjF;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,cAAc,GAC7B,uBAAuB,CAUzB"}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readTreeFile = readTreeFile;
4
+ exports.loadSourceFile = loadSourceFile;
5
+ exports.saveSourceFile = saveSourceFile;
6
+ exports.throwIfNotFound = throwIfNotFound;
7
+ exports.propertyExists = propertyExists;
8
+ exports.findFirstClass = findFirstClass;
9
+ exports.findFirstConstructor = findFirstConstructor;
10
+ exports.findSuperCall = findSuperCall;
11
+ exports.getObjectLiteralFromFirstArg = getObjectLiteralFromFirstArg;
12
+ const ts_morph_1 = require("ts-morph");
13
+ /* -------------------------------------------
14
+ * Utilities
15
+ * -----------------------------------------*/
16
+ /**
17
+ * Reads the content of a file from the Nx Tree.
18
+ * Throws an error if the file cannot be read.
19
+ */
20
+ function readTreeFile(tree, filePath) {
21
+ const content = tree.read(filePath, 'utf-8');
22
+ if (!content) {
23
+ throw new Error(`Could not read file at ${filePath}`);
24
+ }
25
+ return content;
26
+ }
27
+ /**
28
+ * Loads a file from the Nx Tree into a ts-morph Project.
29
+ * Uses `readTreeFile` to get content.
30
+ */
31
+ function loadSourceFile(tree, filePath, project) {
32
+ const content = readTreeFile(tree, filePath);
33
+ return project.createSourceFile(filePath, content, { overwrite: true });
34
+ }
35
+ /**
36
+ * Saves the updated source file content back to the Nx Tree.
37
+ */
38
+ function saveSourceFile(tree, filePath, sourceFileContent) {
39
+ tree.write(filePath, sourceFileContent);
40
+ console.log(`✅ Updated ${filePath}`);
41
+ }
42
+ /**
43
+ * Throws an error if the provided item is null or undefined.
44
+ * Returns the item with a non-null/undefined type assertion.
45
+ */
46
+ function throwIfNotFound(item, message) {
47
+ if (item === null || item === undefined) {
48
+ throw new Error(message);
49
+ }
50
+ return item;
51
+ }
52
+ /**
53
+ * Checks if a property exists in an ObjectLiteralExpression, handling quoted keys.
54
+ */
55
+ function propertyExists(objectLiteral, propName) {
56
+ return objectLiteral.getProperties().some((prop) => {
57
+ if (prop.getKind() === ts_morph_1.SyntaxKind.PropertyAssignment) {
58
+ const assignment = prop;
59
+ // Get the text of the property name node, and remove any quotes
60
+ const name = assignment.getNameNode().getText().replace(/['"]/g, '');
61
+ return name === propName;
62
+ }
63
+ return false;
64
+ });
65
+ }
66
+ /**
67
+ * Finds the first ClassDeclaration in a SourceFile.
68
+ */
69
+ function findFirstClass(sourceFile) {
70
+ const clazz = sourceFile.getClasses()[0];
71
+ return throwIfNotFound(clazz, `No class found in ${sourceFile.getFilePath()}`);
72
+ }
73
+ /**
74
+ * Finds the first ConstructorDeclaration in a ClassDeclaration.
75
+ */
76
+ function findFirstConstructor(clazz) {
77
+ const constructor = clazz.getConstructors()[0];
78
+ return throwIfNotFound(constructor, `No constructor found in class ${clazz.getName() || ''}`);
79
+ }
80
+ /**
81
+ * Finds the `super()` CallExpression within a ConstructorDeclaration.
82
+ */
83
+ function findSuperCall(constructor) {
84
+ const superCall = constructor
85
+ .getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)
86
+ .find((call) => call.getExpression().getKind() === ts_morph_1.SyntaxKind.SuperKeyword);
87
+ return throwIfNotFound(superCall, `Could not find super() call in constructor.`);
88
+ }
89
+ /**
90
+ * Gets the first argument of a CallExpression, asserting it's an ObjectLiteralExpression.
91
+ */
92
+ function getObjectLiteralFromFirstArg(callExpression) {
93
+ const args = callExpression.getArguments();
94
+ throwIfNotFound(args.length, `Call expression has no arguments.`);
95
+ const objectLiteral = args[0];
96
+ throwIfNotFound(objectLiteral &&
97
+ objectLiteral.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression, `First argument is not an object literal.`);
98
+ return objectLiteral;
99
+ }
@@ -0,0 +1,18 @@
1
+ import { Tree } from '@nx/devkit';
2
+ export interface UnisphereConfig {
3
+ company: string;
4
+ name: string;
5
+ }
6
+ export declare function validateUnisphereConfig(tree: Tree): UnisphereConfig;
7
+ export declare function updateTsConfigPaths(tree: Tree, pathKey: string, pathValue: string): void;
8
+ export declare function updateUnisphereConfig(tree: Tree, elementType: 'packages' | 'runtimes' | 'applications', elementName: string, elementConfig: Record<string, any>): void;
9
+ export declare function validateRuntimeExists(tree: Tree, runtimeName: string): string;
10
+ export declare function findCorePackageAlias(tree: Tree): string;
11
+ type NameTransformations<Prefix extends string> = {
12
+ [K in `${Prefix}` | `${Prefix}__lowerDashCase` | `${Prefix}__camelCase` | `${Prefix}__pascalCase` | `${Prefix}__constantCase` | `${Prefix}__humanReadable`]: string;
13
+ };
14
+ export declare function createNameTransforms<Prefix extends string>(baseName: string, prefix: Prefix): NameTransformations<Prefix>;
15
+ export declare function isPackageInstalled(tree: Tree, packageName: string): string | false;
16
+ export declare function checkIfRuntimeExists(tree: Tree, runtimeName: string): boolean;
17
+ export {};
18
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/generators/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAKL,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,IAAI,GAAG,eAAe,CAmDnE;AAGD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,QA4BjF;AAED,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,UAAU,GAAG,UAAU,GAAG,cAAc,EACrD,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QA2BnC;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CA6C7E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CA8BvD;AAGD,KAAK,mBAAmB,CAAC,MAAM,SAAS,MAAM,IAAI;KAC/C,CAAC,IACE,GAAG,MAAM,EAAE,GACX,GAAG,MAAM,iBAAiB,GAC1B,GAAG,MAAM,aAAa,GACtB,GAAG,MAAM,cAAc,GACvB,GAAG,MAAM,gBAAgB,GACzB,GAAG,MAAM,iBAAiB,GAAG,MAAM;CACxC,CAAC;AAKF,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAczH;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAwBlF;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAgB7E"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateUnisphereConfig = validateUnisphereConfig;
4
+ exports.updateTsConfigPaths = updateTsConfigPaths;
5
+ exports.updateUnisphereConfig = updateUnisphereConfig;
6
+ exports.validateRuntimeExists = validateRuntimeExists;
7
+ exports.findCorePackageAlias = findCorePackageAlias;
8
+ exports.createNameTransforms = createNameTransforms;
9
+ exports.isPackageInstalled = isPackageInstalled;
10
+ exports.checkIfRuntimeExists = checkIfRuntimeExists;
11
+ const devkit_1 = require("@nx/devkit");
12
+ function validateUnisphereConfig(tree) {
13
+ // Check if file exists
14
+ if (!tree.exists('.unisphere')) {
15
+ throw new Error('Missing .unisphere configuration file in root project.\n' +
16
+ 'Please create .unisphere with the following structure:\n' +
17
+ '{\n' +
18
+ ' "company": "Your Company Name",\n' +
19
+ ' "name": "your-experience-name"\n' +
20
+ '}');
21
+ }
22
+ // Read and parse JSON
23
+ let config;
24
+ try {
25
+ config = (0, devkit_1.readJson)(tree, '.unisphere');
26
+ }
27
+ catch (error) {
28
+ throw new Error(`Failed to read .unisphere: ${error instanceof Error ? error.message : 'Unknown error'}\n` + 'Please ensure the file contains valid JSON.');
29
+ }
30
+ // Validate required fields
31
+ const missingFields = [];
32
+ if (!config.company) {
33
+ missingFields.push('"company"');
34
+ }
35
+ if (!config.name) {
36
+ missingFields.push('"name"');
37
+ }
38
+ if (missingFields.length > 0) {
39
+ throw new Error(`Missing required field${missingFields.length > 1 ? 's' : ''} ${missingFields.join(' and ')} in .unisphere.\n` +
40
+ 'Please ensure your .unisphere contains:\n' +
41
+ '{\n' +
42
+ ' "company": "Your Company Name",\n' +
43
+ ' "name": "your-experience-name"\n' +
44
+ '}');
45
+ }
46
+ return {
47
+ company: config.company,
48
+ name: config.name,
49
+ };
50
+ }
51
+ function updateTsConfigPaths(tree, pathKey, pathValue) {
52
+ if (tree.exists('tsconfig.base.json')) {
53
+ try {
54
+ const tsconfigBase = (0, devkit_1.readJson)(tree, 'tsconfig.base.json');
55
+ // Ensure compilerOptions and paths exist
56
+ if (!tsconfigBase.compilerOptions) {
57
+ tsconfigBase.compilerOptions = {};
58
+ }
59
+ if (!tsconfigBase.compilerOptions.paths) {
60
+ tsconfigBase.compilerOptions.paths = {};
61
+ }
62
+ // Add the path mapping (only if it doesn't already exist)
63
+ if (!tsconfigBase.compilerOptions.paths[pathKey]) {
64
+ tsconfigBase.compilerOptions.paths[pathKey] = [pathValue];
65
+ }
66
+ // Write the updated tsconfig back
67
+ (0, devkit_1.writeJson)(tree, 'tsconfig.base.json', tsconfigBase);
68
+ }
69
+ catch (error) {
70
+ throw new Error(`Failed to update tsconfig.base.json: ${error instanceof Error ? error.message : 'Unknown error'}`);
71
+ }
72
+ }
73
+ }
74
+ function updateUnisphereConfig(tree, elementType, elementName, elementConfig) {
75
+ const existingConfig = (0, devkit_1.readJson)(tree, '.unisphere');
76
+ // Ensure elements structure exists
77
+ if (!existingConfig.elements) {
78
+ existingConfig.elements = {};
79
+ }
80
+ if (!existingConfig.elements[elementType]) {
81
+ existingConfig.elements[elementType] = {};
82
+ }
83
+ // Add the new element entry (only if it doesn't already exist)
84
+ if (!existingConfig.elements[elementType][elementName]) {
85
+ existingConfig.elements[elementType][elementName] = elementConfig;
86
+ }
87
+ // Write the updated configuration back
88
+ try {
89
+ (0, devkit_1.writeJson)(tree, '.unisphere', existingConfig);
90
+ }
91
+ catch (error) {
92
+ throw new Error(`Failed to update .unisphere: ${error instanceof Error ? error.message : 'Unknown error'}`);
93
+ }
94
+ }
95
+ function validateRuntimeExists(tree, runtimeName) {
96
+ // First validate that .unisphere exists
97
+ if (!tree.exists('.unisphere')) {
98
+ throw new Error('Missing .unisphere configuration file in root project.');
99
+ }
100
+ // Read and parse the .unisphere configuration
101
+ let config;
102
+ try {
103
+ config = (0, devkit_1.readJson)(tree, '.unisphere');
104
+ }
105
+ catch (error) {
106
+ throw new Error(`Failed to read .unisphere: ${error instanceof Error ? error.message : 'Unknown error'}\n` + 'Please ensure the file contains valid JSON.');
107
+ }
108
+ // Check if elements.runtimes exists
109
+ if (!config.elements?.runtimes) {
110
+ throw new Error(`No runtimes found in .unisphere configuration.\n` +
111
+ `Runtime "${runtimeName}" not found.\n` +
112
+ 'Please create a runtime first using: nx generate @unisphere/nx:add-runtime');
113
+ }
114
+ // Check if the specific runtime exists
115
+ const runtimeConfig = config.elements.runtimes[runtimeName];
116
+ if (!runtimeConfig) {
117
+ throw new Error(`Runtime "${runtimeName}" not found in .unisphere configuration.`);
118
+ }
119
+ // Check if sourceRoot exists
120
+ if (!runtimeConfig.sourceRoot) {
121
+ throw new Error(`Runtime "${runtimeName}" exists but has no sourceRoot configured`);
122
+ }
123
+ return runtimeConfig.sourceRoot;
124
+ }
125
+ function findCorePackageAlias(tree) {
126
+ if (!tree.exists('tsconfig.base.json')) {
127
+ throw new Error('tsconfig.base.json not found in the project root.');
128
+ }
129
+ try {
130
+ const tsconfigBase = (0, devkit_1.readJson)(tree, 'tsconfig.base.json');
131
+ if (!tsconfigBase.compilerOptions?.paths) {
132
+ throw new Error('No paths found in tsconfig.base.json compilerOptions.');
133
+ }
134
+ // Find the key that has the value "unisphere/packages/core/src/index.ts"
135
+ for (const [key, paths] of Object.entries(tsconfigBase.compilerOptions.paths)) {
136
+ if (Array.isArray(paths) && paths.includes('unisphere/packages/core/src/index.ts')) {
137
+ return key;
138
+ }
139
+ }
140
+ throw new Error('Core package not found in tsconfig.base.json paths. ' +
141
+ 'Expected to find a key with value "unisphere/packages/core/src/index.ts"');
142
+ }
143
+ catch (error) {
144
+ throw new Error(`Failed to read tsconfig.base.json: ${error instanceof Error ? error.message : 'Unknown error'}`);
145
+ }
146
+ }
147
+ function createNameTransforms(baseName, prefix) {
148
+ const nameVariants = (0, devkit_1.names)(baseName); // Assuming 'names' function is available and returns NameVariants
149
+ const humanReadable = baseName
150
+ .replace(/[-_]/g, ' ')
151
+ .replace(/\b\w/g, (l) => l.toUpperCase());
152
+ return {
153
+ [`${prefix}`]: baseName,
154
+ [`${prefix}__lowerDashCase`]: nameVariants.fileName,
155
+ [`${prefix}__camelCase`]: nameVariants.propertyName,
156
+ [`${prefix}__pascalCase`]: nameVariants.className,
157
+ [`${prefix}__constantCase`]: nameVariants.constantName,
158
+ [`${prefix}__humanReadable`]: humanReadable,
159
+ }; // Type assertion to match the defined type
160
+ }
161
+ function isPackageInstalled(tree, packageName) {
162
+ // Check if package.json exists
163
+ if (!tree.exists('package.json')) {
164
+ devkit_1.logger.warn('⚠️ package.json not found in root directory');
165
+ return false;
166
+ }
167
+ try {
168
+ const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
169
+ // Check all dependency types
170
+ const allDependencies = {
171
+ ...packageJson.dependencies,
172
+ ...packageJson.devDependencies,
173
+ ...packageJson.peerDependencies,
174
+ };
175
+ const installedVersion = allDependencies[packageName];
176
+ return installedVersion || false;
177
+ }
178
+ catch (error) {
179
+ devkit_1.logger.warn(`⚠️ Failed to read package.json: ${error instanceof Error ? error.message : 'Unknown error'}`);
180
+ return false;
181
+ }
182
+ }
183
+ function checkIfRuntimeExists(tree, runtimeName) {
184
+ // Check if .unisphere file exists
185
+ if (!tree.exists('.unisphere')) {
186
+ return false;
187
+ }
188
+ try {
189
+ // Read and parse the .unisphere configuration
190
+ const config = (0, devkit_1.readJson)(tree, '.unisphere');
191
+ // Check if elements.runtimes exists and contains the runtime
192
+ return !!(config.elements?.runtimes?.[runtimeName]);
193
+ }
194
+ catch (error) {
195
+ // If there's any error reading/parsing the file, return false
196
+ return false;
197
+ }
198
+ }