@unisphere/nx 4.10.1 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generators/add-runtime/add-runtime.d.ts +1 -1
- package/dist/generators/add-runtime/add-runtime.d.ts.map +1 -1
- package/dist/generators/add-runtime/add-runtime.js +149 -0
- package/dist/generators/add-runtime/schema.d.ts +1 -0
- package/dist/generators/add-runtime/schema.json +5 -0
- package/dist/generators/add-runtime/templates/new-flavor/runtime-__flavorName__.tsx.template +63 -0
- package/dist/generators/add-runtime/templates/new-flavor-types/runtime-__flavorName__-types.ts.template +20 -0
- package/dist/generators/add-runtime/templates/new-runtime/src/lib/runtime.tsx.template +1 -1
- package/dist/generators/add-visual/add-visual.d.ts +2 -0
- package/dist/generators/add-visual/add-visual.d.ts.map +1 -1
- package/dist/generators/add-visual/add-visual.js +45 -22
- package/dist/generators/add-visual/schema.d.ts +1 -0
- package/dist/generators/add-visual/schema.json +4 -0
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Tree } from '@nx/devkit';
|
|
2
2
|
import { AddRuntimeGeneratorSchema } from './schema';
|
|
3
|
-
export declare function addRuntimeGenerator(tree: Tree, options: AddRuntimeGeneratorSchema): Promise<
|
|
3
|
+
export declare function addRuntimeGenerator(tree: Tree, options: AddRuntimeGeneratorSchema): Promise<any>;
|
|
4
4
|
export default addRuntimeGenerator;
|
|
5
5
|
//# sourceMappingURL=add-runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-runtime.d.ts","sourceRoot":"","sources":["../../../src/generators/add-runtime/add-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAsC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"add-runtime.d.ts","sourceRoot":"","sources":["../../../src/generators/add-runtime/add-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAsC,MAAM,YAAY,CAAC;AAUlG,OAAO,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AA0SrD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,yBAAyB,gBAgHnC;AAED,eAAe,mBAAmB,CAAC"}
|
|
@@ -4,8 +4,10 @@ exports.addRuntimeGenerator = addRuntimeGenerator;
|
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
const ts_morph_1 = require("ts-morph");
|
|
7
8
|
const utils_1 = require("../utils");
|
|
8
9
|
const dependency_config_1 = require("../dependency-config");
|
|
10
|
+
const visual_utils_1 = require("../add-visual/visual-utils");
|
|
9
11
|
function validateOptions(options) {
|
|
10
12
|
if (!options.name || options.name.trim() === '') {
|
|
11
13
|
throw new Error(`Missing required option: 'name'\n` +
|
|
@@ -21,6 +23,150 @@ function validateOptions(options) {
|
|
|
21
23
|
` Received: ${options.name}`);
|
|
22
24
|
}
|
|
23
25
|
}
|
|
26
|
+
function validateFlavorName(flavor) {
|
|
27
|
+
if (!flavor || flavor.trim() === '') {
|
|
28
|
+
throw new Error(`Missing required option: 'flavor'\n` +
|
|
29
|
+
` Description: The name of the flavor to add\n` +
|
|
30
|
+
` Pattern: ^[a-zA-Z][a-zA-Z0-9\\-\\s]*$`);
|
|
31
|
+
}
|
|
32
|
+
const namePattern = /^[a-zA-Z][a-zA-Z0-9\-\s]*$/;
|
|
33
|
+
if (!namePattern.test(flavor)) {
|
|
34
|
+
throw new Error(`Invalid value '${flavor}' for option 'flavor'\n` +
|
|
35
|
+
` Pattern: ^[a-zA-Z][a-zA-Z0-9\\-\\s]*$\n` +
|
|
36
|
+
` Received: ${flavor}`);
|
|
37
|
+
}
|
|
38
|
+
if ((0, devkit_1.names)(flavor).fileName === 'default') {
|
|
39
|
+
throw new Error(`Flavor name 'default' is reserved. The default flavor is runtime.tsx.\n` +
|
|
40
|
+
` Please choose a different flavor name.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function updateCreateFactory(tree, sourceRoot, flavorNames, project) {
|
|
44
|
+
const factoryPath = [`${sourceRoot}/src/lib/create-factory.tsx`, `${sourceRoot}/src/lib/create-factory.ts`]
|
|
45
|
+
.find((p) => tree.exists(p));
|
|
46
|
+
if (!factoryPath) {
|
|
47
|
+
throw new Error(`Create factory file not found in ${sourceRoot}/src/lib/.\n` +
|
|
48
|
+
` Expected: create-factory.tsx or create-factory.ts`);
|
|
49
|
+
}
|
|
50
|
+
const sourceFile = (0, visual_utils_1.loadSourceFile)(tree, factoryPath, project);
|
|
51
|
+
const flavorLowerDash = flavorNames['flavorName__lowerDashCase'];
|
|
52
|
+
const flavorPascal = flavorNames['flavorName__pascalCase'];
|
|
53
|
+
const className = `Runtime${flavorPascal}`;
|
|
54
|
+
const alreadyImported = sourceFile
|
|
55
|
+
.getImportDeclarations()
|
|
56
|
+
.some((decl) => decl.getNamedImports().some((imp) => imp.getName() === className));
|
|
57
|
+
if (alreadyImported) {
|
|
58
|
+
console.log(`⚠️ Import for ${className} already exists in create-factory.`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
sourceFile.addImportDeclaration({
|
|
62
|
+
kind: ts_morph_1.StructureKind.ImportDeclaration,
|
|
63
|
+
namedImports: [className],
|
|
64
|
+
moduleSpecifier: `./runtime-${flavorLowerDash}`,
|
|
65
|
+
});
|
|
66
|
+
const switchStatement = sourceFile.getDescendantsOfKind(ts_morph_1.SyntaxKind.SwitchStatement)[0];
|
|
67
|
+
if (!switchStatement) {
|
|
68
|
+
const createMethod = sourceFile
|
|
69
|
+
.getDescendantsOfKind(ts_morph_1.SyntaxKind.MethodDeclaration)
|
|
70
|
+
.find((m) => m.getName() === 'create');
|
|
71
|
+
(0, visual_utils_1.throwIfNotFound)(createMethod, `No 'create' method found in ${factoryPath}`);
|
|
72
|
+
const returnStatement = createMethod.getDescendantsOfKind(ts_morph_1.SyntaxKind.ReturnStatement)[0];
|
|
73
|
+
(0, visual_utils_1.throwIfNotFound)(returnStatement, `No return statement found in create method in ${factoryPath}`);
|
|
74
|
+
const returnExpr = returnStatement.getExpression()?.getText() || 'new Runtime(options)';
|
|
75
|
+
returnStatement.replaceWithText(`switch (options.flavor) {\n` +
|
|
76
|
+
` case '${flavorLowerDash}':\n` +
|
|
77
|
+
` return new ${className}(options) as any;\n` +
|
|
78
|
+
` default:\n` +
|
|
79
|
+
` return ${returnExpr};\n` +
|
|
80
|
+
` }`);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const caseBlock = switchStatement.getCaseBlock();
|
|
84
|
+
const cases = caseBlock.getClauses();
|
|
85
|
+
const caseExists = cases.some((c) => {
|
|
86
|
+
if (c.getKind() === ts_morph_1.SyntaxKind.CaseClause) {
|
|
87
|
+
const clause = c;
|
|
88
|
+
return clause.getExpression()?.getText().replace(/['"]/g, '') === flavorLowerDash;
|
|
89
|
+
}
|
|
90
|
+
return false;
|
|
91
|
+
});
|
|
92
|
+
if (caseExists) {
|
|
93
|
+
console.log(`⚠️ Switch case for flavor '${flavorLowerDash}' already exists.`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const newCase = `case '${flavorLowerDash}':\n return new ${className}(options) as any;`;
|
|
97
|
+
const defaultIndex = cases.findIndex((c) => c.getKind() === ts_morph_1.SyntaxKind.DefaultClause);
|
|
98
|
+
if (defaultIndex !== -1) {
|
|
99
|
+
const defaultClause = cases[defaultIndex];
|
|
100
|
+
defaultClause.replaceWithText(`${newCase}\n ${defaultClause.getText()}`);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
const lastCase = cases[cases.length - 1];
|
|
104
|
+
lastCase.replaceWithText(`${lastCase.getText()}\n ${newCase}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
(0, visual_utils_1.saveSourceFile)(tree, factoryPath, sourceFile.getFullText());
|
|
108
|
+
console.log(`✅ Updated create-factory with flavor '${flavorLowerDash}'`);
|
|
109
|
+
}
|
|
110
|
+
function updateFlavorTypesIndexExport(tree, runtimeName, flavorLowerDash, typesPackageInfo) {
|
|
111
|
+
const indexPath = `${typesPackageInfo.basePath}/src/lib/${runtimeName}-runtime/index.ts`;
|
|
112
|
+
if (!tree.exists(indexPath)) {
|
|
113
|
+
throw new Error(`Runtime types index not found at ${indexPath}`);
|
|
114
|
+
}
|
|
115
|
+
const currentContent = tree.read(indexPath, 'utf-8');
|
|
116
|
+
if (!currentContent) {
|
|
117
|
+
throw new Error(`Failed to read content from ${indexPath}`);
|
|
118
|
+
}
|
|
119
|
+
const exportLine = `export * from './runtime-${flavorLowerDash}-types';`;
|
|
120
|
+
if (currentContent.includes(exportLine)) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const updatedContent = currentContent.replace(/\n\n$/, '\n') + exportLine;
|
|
124
|
+
tree.write(indexPath, updatedContent);
|
|
125
|
+
}
|
|
126
|
+
async function addFlavorToRuntime(tree, options) {
|
|
127
|
+
const runtimeName = (0, devkit_1.names)(options.name).fileName;
|
|
128
|
+
const flavor = options.flavor;
|
|
129
|
+
validateFlavorName(flavor);
|
|
130
|
+
const unisphereConfig = (0, utils_1.validateUnisphereConfig)(tree);
|
|
131
|
+
const sourceRoot = (0, utils_1.validateRuntimeExists)(tree, runtimeName);
|
|
132
|
+
const typesPackageInfo = (0, utils_1.findTypesOrCorePackageInfo)(tree);
|
|
133
|
+
const flavorLowerDash = (0, devkit_1.names)(flavor).fileName;
|
|
134
|
+
const flavorFilePath = `${sourceRoot}/src/lib/runtime-${flavorLowerDash}.tsx`;
|
|
135
|
+
if (tree.exists(flavorFilePath)) {
|
|
136
|
+
throw new Error(`Flavor file already exists at ${flavorFilePath}.\n` +
|
|
137
|
+
` Choose a different flavor name or remove the existing file.`);
|
|
138
|
+
}
|
|
139
|
+
const flavorTypesPath = `${typesPackageInfo.basePath}/src/lib/${runtimeName}-runtime/runtime-${flavorLowerDash}-types.ts`;
|
|
140
|
+
if (tree.exists(flavorTypesPath)) {
|
|
141
|
+
throw new Error(`Flavor types file already exists at ${flavorTypesPath}.\n` +
|
|
142
|
+
` Choose a different flavor name or remove the existing file.`);
|
|
143
|
+
}
|
|
144
|
+
const runtimeNames = (0, utils_1.createNameTransforms)(runtimeName, 'runtimeName');
|
|
145
|
+
const flavorNames = (0, utils_1.createNameTransforms)(flavorLowerDash, 'flavorName');
|
|
146
|
+
const widgetNames = (0, utils_1.createNameTransforms)(unisphereConfig.name, 'widgetName');
|
|
147
|
+
const templateVariables = {
|
|
148
|
+
...runtimeNames,
|
|
149
|
+
...flavorNames,
|
|
150
|
+
...widgetNames,
|
|
151
|
+
typesAlias: typesPackageInfo.alias,
|
|
152
|
+
tmpl: '',
|
|
153
|
+
};
|
|
154
|
+
(0, devkit_1.generateFiles)(tree, path.join(__dirname, 'templates/new-flavor'), `${sourceRoot}/src/lib`, templateVariables);
|
|
155
|
+
(0, devkit_1.generateFiles)(tree, path.join(__dirname, 'templates/new-flavor-types'), `${typesPackageInfo.basePath}/src/lib/${runtimeName}-runtime`, templateVariables);
|
|
156
|
+
updateFlavorTypesIndexExport(tree, runtimeName, flavorLowerDash, typesPackageInfo);
|
|
157
|
+
const project = new ts_morph_1.Project({
|
|
158
|
+
useInMemoryFileSystem: true,
|
|
159
|
+
skipAddingFilesFromTsConfig: true,
|
|
160
|
+
});
|
|
161
|
+
updateCreateFactory(tree, sourceRoot, flavorNames, project);
|
|
162
|
+
await (0, devkit_1.formatFiles)(tree);
|
|
163
|
+
console.log(`\n🎉 Successfully added flavor '${flavorLowerDash}' to runtime '${runtimeName}'!`);
|
|
164
|
+
console.log(` Flavor file: ${flavorFilePath}`);
|
|
165
|
+
console.log(` Types file: ${flavorTypesPath}`);
|
|
166
|
+
return () => {
|
|
167
|
+
return { runtimeName, flavor: flavorLowerDash };
|
|
168
|
+
};
|
|
169
|
+
}
|
|
24
170
|
function updateTypesIndexExport(tree, runtimeName, basePath) {
|
|
25
171
|
const indexPath = `${basePath}/src/index.ts`;
|
|
26
172
|
if (!tree.exists(indexPath)) {
|
|
@@ -41,6 +187,9 @@ function updateTypesIndexExport(tree, runtimeName, basePath) {
|
|
|
41
187
|
}
|
|
42
188
|
async function addRuntimeGenerator(tree, options) {
|
|
43
189
|
validateOptions(options);
|
|
190
|
+
if (options.flavor) {
|
|
191
|
+
return addFlavorToRuntime(tree, options);
|
|
192
|
+
}
|
|
44
193
|
// Validate and read .unisphere configuration
|
|
45
194
|
const unisphereConfig = (0, utils_1.validateUnisphereConfig)(tree);
|
|
46
195
|
// Validate dependencies
|
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
"analyticsAppId": {
|
|
22
22
|
"type": "number",
|
|
23
23
|
"description": "Analytics app ID (optional, can be set later in runtime constructor)"
|
|
24
|
+
},
|
|
25
|
+
"flavor": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"description": "Name of the flavor to add to an existing runtime (e.g. 'player-plugin')",
|
|
28
|
+
"pattern": "^[a-zA-Z][a-zA-Z0-9\\-\\s]*$"
|
|
24
29
|
}
|
|
25
30
|
},
|
|
26
31
|
"required": [
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import * as ReactDOM from 'react-dom/client';
|
|
2
|
+
import { Root } from 'react-dom/client';
|
|
3
|
+
import {
|
|
4
|
+
CreateElementOptions,
|
|
5
|
+
UnisphereRuntimeBase,
|
|
6
|
+
} from '@unisphere/runtime-js';
|
|
7
|
+
import {
|
|
8
|
+
<%= runtimeName__pascalCase %>Runtime<%= flavorName__pascalCase %>Settings,
|
|
9
|
+
<%= runtimeName__camelCase %>Runtime<%= flavorName__pascalCase %>SettingsSchema,
|
|
10
|
+
<%= runtimeName__pascalCase %>RuntimeName,
|
|
11
|
+
<%= runtimeName__pascalCase %><%= flavorName__pascalCase %>Runtime,
|
|
12
|
+
widgetName,
|
|
13
|
+
} from '<%= typesAlias %>';
|
|
14
|
+
import { HtmlDomRuntimeVisual } from '@unisphere/runtime';
|
|
15
|
+
|
|
16
|
+
export class Runtime<%= flavorName__pascalCase %>
|
|
17
|
+
extends UnisphereRuntimeBase<<%= runtimeName__pascalCase %>Runtime<%= flavorName__pascalCase %>Settings, Root>
|
|
18
|
+
implements <%= runtimeName__pascalCase %><%= flavorName__pascalCase %>Runtime {
|
|
19
|
+
readonly id = widgetName;
|
|
20
|
+
readonly runtime = <%= runtimeName__pascalCase %>RuntimeName;
|
|
21
|
+
readonly widgetName = widgetName;
|
|
22
|
+
readonly runtimeName = <%= runtimeName__pascalCase %>RuntimeName;
|
|
23
|
+
readonly flavor = '<%= flavorName__lowerDashCase %>';
|
|
24
|
+
|
|
25
|
+
protected _onKilled(): void {
|
|
26
|
+
this._logger.log('runtime killed');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
constructor(options: CreateElementOptions<<%= runtimeName__pascalCase %>Runtime<%= flavorName__pascalCase %>Settings>) {
|
|
30
|
+
super({
|
|
31
|
+
...options,
|
|
32
|
+
settingsSchema: <%= runtimeName__camelCase %>Runtime<%= flavorName__pascalCase %>SettingsSchema,
|
|
33
|
+
visualTypes: {},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
this._logger.log('runtime initialized', {
|
|
37
|
+
data: {
|
|
38
|
+
widgetName: this.widgetName,
|
|
39
|
+
runtimeName: this.runtimeName,
|
|
40
|
+
flavor: this.flavor,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override _createVisualContainer(htmlElement: HTMLElement): Root {
|
|
46
|
+
return ReactDOM.createRoot(htmlElement);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
override _onVisualMount(visual: HtmlDomRuntimeVisual<Root>) {
|
|
50
|
+
switch (visual.type) {
|
|
51
|
+
default:
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override _onVisualUnmount(visual: HtmlDomRuntimeVisual<Root>) {
|
|
57
|
+
visual.htmlContainer?.unmount();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected _onSettingsUpdated(settings: <%= runtimeName__pascalCase %>Runtime<%= flavorName__pascalCase %>Settings) {
|
|
61
|
+
// use this method to react to settings changes
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ValidatorSchema } from '@unisphere/core';
|
|
2
|
+
import { UnisphereRuntimeBaseType } from '@unisphere/runtime';
|
|
3
|
+
import { widgetName } from '../widget-types';
|
|
4
|
+
import { <%= runtimeName__pascalCase %>RuntimeName } from './runtime-types';
|
|
5
|
+
|
|
6
|
+
export interface <%= runtimeName__pascalCase %>Runtime<%= flavorName__pascalCase %>Settings {
|
|
7
|
+
schemaVersion?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const <%= runtimeName__camelCase %>Runtime<%= flavorName__pascalCase %>SettingsSchema: ValidatorSchema = {
|
|
11
|
+
type: 'object',
|
|
12
|
+
properties: {
|
|
13
|
+
schemaVersion: { type: 'literal', value: '1', optional: true },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type <%= runtimeName__pascalCase %><%= flavorName__pascalCase %>Runtime = UnisphereRuntimeBaseType<<%= runtimeName__pascalCase %>Runtime<%= flavorName__pascalCase %>Settings> & {
|
|
18
|
+
readonly widgetName: typeof widgetName;
|
|
19
|
+
readonly runtimeName: typeof <%= runtimeName__pascalCase %>RuntimeName;
|
|
20
|
+
}
|
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
<%= runtimeName__pascalCase %>RuntimeName,
|
|
10
10
|
<%= runtimeName__pascalCase %>RuntimeSettings,
|
|
11
11
|
<%= runtimeName__camelCase %>RuntimeSettingsSchema,
|
|
12
|
+
widgetName,
|
|
12
13
|
} from '<%= typesAlias %>';
|
|
13
14
|
import { HtmlDomRuntimeVisual, KalturaAnalyticsServiceType } from '@unisphere/runtime';
|
|
14
|
-
import { widgetName } from '<%= typesAlias %>'
|
|
15
15
|
|
|
16
16
|
export class Runtime
|
|
17
17
|
extends UnisphereRuntimeBase<<%= runtimeName__pascalCase %>RuntimeSettings, Root>
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Tree } from '@nx/devkit';
|
|
2
2
|
import { AddVisualGeneratorSchema } from './schema';
|
|
3
|
+
export declare function discoverAvailableFlavors(tree: Tree, sourceRoot: string): string[];
|
|
4
|
+
export declare function resolveTargetFile(tree: Tree, sourceRoot: string, flavor: string | undefined): string;
|
|
3
5
|
/**
|
|
4
6
|
* Nx generator to create a new visual within a specified runtime.
|
|
5
7
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-visual.d.ts","sourceRoot":"","sources":["../../../src/generators/add-visual/add-visual.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAE,MAAM,YAAY,CAAC;AAsB9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"add-visual.d.ts","sourceRoot":"","sources":["../../../src/generators/add-visual/add-visual.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,IAAI,EAAE,MAAM,YAAY,CAAC;AAsB9D,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAC;AAapD,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE,CAUjF;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,CAuBR;AAwZD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,GAAG,CAAC,CA6Ed;AAED,eAAe,kBAAkB,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.discoverAvailableFlavors = discoverAvailableFlavors;
|
|
4
|
+
exports.resolveTargetFile = resolveTargetFile;
|
|
3
5
|
exports.addVisualGenerator = addVisualGenerator;
|
|
4
6
|
const tslib_1 = require("tslib");
|
|
5
7
|
const devkit_1 = require("@nx/devkit");
|
|
@@ -7,6 +9,37 @@ const path = tslib_1.__importStar(require("path"));
|
|
|
7
9
|
const ts_morph_1 = require("ts-morph");
|
|
8
10
|
const utils_1 = require("../utils");
|
|
9
11
|
const visual_utils_1 = require("./visual-utils");
|
|
12
|
+
function discoverAvailableFlavors(tree, sourceRoot) {
|
|
13
|
+
const libDir = `${sourceRoot}/src/lib`;
|
|
14
|
+
if (!tree.exists(libDir)) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
return tree
|
|
18
|
+
.children(libDir)
|
|
19
|
+
.filter((f) => /^(runtime-.+|.+-runtime-base)\.tsx$/.test(f))
|
|
20
|
+
.map((f) => f.replace('.tsx', ''))
|
|
21
|
+
.sort();
|
|
22
|
+
}
|
|
23
|
+
function resolveTargetFile(tree, sourceRoot, flavor) {
|
|
24
|
+
const libDir = `${sourceRoot}/src/lib`;
|
|
25
|
+
if (!flavor) {
|
|
26
|
+
const defaultPath = `${libDir}/runtime.tsx`;
|
|
27
|
+
if (!tree.exists(defaultPath)) {
|
|
28
|
+
throw new Error(`Default runtime file not found at ${defaultPath}`);
|
|
29
|
+
}
|
|
30
|
+
return defaultPath;
|
|
31
|
+
}
|
|
32
|
+
const targetPath = `${libDir}/${flavor}.tsx`;
|
|
33
|
+
if (!tree.exists(targetPath)) {
|
|
34
|
+
const available = discoverAvailableFlavors(tree, sourceRoot);
|
|
35
|
+
throw new Error(`Flavor file '${flavor}.tsx' not found in ${libDir}.\n` +
|
|
36
|
+
(available.length > 0
|
|
37
|
+
? ` Available flavors: ${available.join(', ')}\n`
|
|
38
|
+
: '') +
|
|
39
|
+
` Omit --flavor to target the default runtime.`);
|
|
40
|
+
}
|
|
41
|
+
return targetPath;
|
|
42
|
+
}
|
|
10
43
|
function validateOptions(options) {
|
|
11
44
|
if (!options.runtimeName || options.runtimeName.trim() === '') {
|
|
12
45
|
throw new Error(`Missing required option: 'runtimeName'\n` +
|
|
@@ -130,8 +163,7 @@ function addVisualTypesToConstructor(sourceFilePath, tree, vars, project, isSing
|
|
|
130
163
|
const visualTypesProp = (0, visual_utils_1.throwIfNotFound)(objectLiteral
|
|
131
164
|
.getProperties()
|
|
132
165
|
.find((prop) => prop.getKind() === ts_morph_1.SyntaxKind.PropertyAssignment &&
|
|
133
|
-
prop.getName()
|
|
134
|
-
`Could not find visualTypes property in super() call in ${sourceFilePath}`);
|
|
166
|
+
['visualTypes', 'flavorVisualTypes'].includes(prop.getName())), `Could not find visualTypes or flavorVisualTypes property in super() call in ${sourceFilePath}`);
|
|
135
167
|
const visualTypesObject = (0, visual_utils_1.throwIfNotFound)(visualTypesProp.getInitializer(), // Assert type after getting initializer
|
|
136
168
|
`visualTypes is not an object literal in ${sourceFilePath}`);
|
|
137
169
|
if ((0, visual_utils_1.propertyExists)(visualTypesObject, visualCamel)) {
|
|
@@ -287,18 +319,14 @@ async function addVisualGenerator(tree, options) {
|
|
|
287
319
|
const isSingleOccurrence = options.isSingleOccurrence ?? false;
|
|
288
320
|
// Extract environment variables
|
|
289
321
|
const widgetName = unisphereConfig.name;
|
|
290
|
-
// Validate runtime existence and get source root path.
|
|
291
322
|
const runtimeSourceRoot = (0, utils_1.validateRuntimeExists)(tree, runtimeName);
|
|
292
|
-
const
|
|
293
|
-
// Find types package (or fallback to core)
|
|
323
|
+
const targetFile = resolveTargetFile(tree, runtimeSourceRoot, options.flavor);
|
|
294
324
|
const typesPackageInfo = (0, utils_1.findTypesOrCorePackageInfo)(tree);
|
|
295
325
|
const runtimeNames = (0, utils_1.createNameTransforms)(runtimeName, 'runtimeName');
|
|
296
326
|
const visualNames = (0, utils_1.createNameTransforms)(visualName, 'visualName');
|
|
297
327
|
const widgetNames = (0, utils_1.createNameTransforms)(widgetName, 'widgetName');
|
|
298
|
-
// Derive specific names for runtime visual settings and schema based on transforms.
|
|
299
328
|
const runtimeVisualSettings = `${runtimeNames.runtimeName__pascalCase}Runtime${visualNames.visualName__pascalCase}VisualSettings`;
|
|
300
329
|
const runtimeVisualSchema = `${runtimeNames.runtimeName__camelCase}Runtime${visualNames.visualName__pascalCase}VisualSettingsSchema`;
|
|
301
|
-
// Combine all template variables for easy access and passing to functions.
|
|
302
330
|
const templateVariables = {
|
|
303
331
|
...runtimeNames,
|
|
304
332
|
...visualNames,
|
|
@@ -307,30 +335,25 @@ async function addVisualGenerator(tree, options) {
|
|
|
307
335
|
runtimeVisualSchema,
|
|
308
336
|
typesAlias: typesPackageInfo.alias,
|
|
309
337
|
};
|
|
310
|
-
// Ensure the target runtime file exists before proceeding.
|
|
311
|
-
if (!tree.exists(runtimeTSxPath)) {
|
|
312
|
-
throw new Error(`Runtime file not found at ${runtimeTSxPath}`);
|
|
313
|
-
}
|
|
314
|
-
// Initialize ts-morph project with an in-memory file system for modifications.
|
|
315
338
|
const project = new ts_morph_1.Project({
|
|
316
339
|
useInMemoryFileSystem: true,
|
|
317
340
|
skipAddingFilesFromTsConfig: true,
|
|
318
341
|
});
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
342
|
+
if (options.flavor) {
|
|
343
|
+
console.log(`\nProcessing flavor '${options.flavor}'...`);
|
|
344
|
+
}
|
|
345
|
+
addImportToRuntime(targetFile, tree, templateVariables, project);
|
|
346
|
+
addVisualTypesToConstructor(targetFile, tree, templateVariables, project, isSingleOccurrence);
|
|
347
|
+
addSwitchCaseToRuntime(targetFile, tree, templateVariables, project);
|
|
348
|
+
addRenderMethod(targetFile, tree, templateVariables, project, typesPackageInfo);
|
|
325
349
|
createVisualTypes(tree, templateVariables, typesPackageInfo);
|
|
326
|
-
// Format all modified files for consistent code style.
|
|
327
350
|
await (0, devkit_1.formatFiles)(tree);
|
|
328
|
-
|
|
329
|
-
console.log(`\n🎉 Successfully added visual '${visualName}' to runtime '${runtimeName}'!`);
|
|
351
|
+
const flavorSummary = options.flavor ? ` (flavor: ${options.flavor})` : '';
|
|
352
|
+
console.log(`\n🎉 Successfully added visual '${visualName}' to runtime '${runtimeName}'${flavorSummary}!`);
|
|
330
353
|
console.log(` Runtime: ${runtimeName} (${runtimeSourceRoot})`);
|
|
354
|
+
console.log(` Target: ${targetFile}`);
|
|
331
355
|
console.log(` Visual: ${visualName}`);
|
|
332
356
|
console.log(` Single occurrence: ${isSingleOccurrence ? 'Yes' : 'No'}`);
|
|
333
|
-
console.log(` Modified file: ${runtimeTSxPath}`);
|
|
334
357
|
return () => {
|
|
335
358
|
return { visualName };
|
|
336
359
|
};
|
|
@@ -18,6 +18,10 @@
|
|
|
18
18
|
"type": "boolean",
|
|
19
19
|
"description": "Whether this visual is limited to single occurrence",
|
|
20
20
|
"default": false
|
|
21
|
+
},
|
|
22
|
+
"flavor": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"description": "Target file name without .tsx extension (e.g. 'runtime-player-plugin', 'chat-runtime-base'). Omit to target the default runtime.tsx."
|
|
21
25
|
}
|
|
22
26
|
},
|
|
23
27
|
"required": ["runtimeName", "visualName"]
|