@reveldigital/player-client 1.0.16 → 2.0.2

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 (58) hide show
  1. package/README.md +236 -236
  2. package/esm2022/lib/app-init.service.mjs +113 -0
  3. package/esm2022/lib/interfaces/client.interface.mjs +2 -0
  4. package/esm2022/lib/interfaces/command.interface.mjs +2 -0
  5. package/esm2022/lib/interfaces/config.interface.mjs +50 -0
  6. package/esm2022/lib/interfaces/device.interface.mjs +2 -0
  7. package/esm2022/lib/interfaces/event-properties.interface.mjs +2 -0
  8. package/esm2022/lib/interfaces/location.interface.mjs +2 -0
  9. package/esm2022/lib/player-client.module.mjs +71 -0
  10. package/esm2022/lib/player-client.service.mjs +928 -0
  11. package/esm2022/lib/safe-style.pipe.mjs +41 -0
  12. package/{esm2020 → esm2022}/lib/version.mjs +3 -3
  13. package/{esm2020 → esm2022}/public-api.mjs +6 -6
  14. package/{esm2020 → esm2022}/reveldigital-player-client.mjs +4 -4
  15. package/{fesm2020 → fesm2022}/reveldigital-player-client.mjs +1132 -1134
  16. package/fesm2022/reveldigital-player-client.mjs.map +1 -0
  17. package/{reveldigital-player-client.d.ts → index.d.ts} +5 -5
  18. package/lib/app-init.service.d.ts +18 -18
  19. package/lib/app-init.service.d.ts.map +1 -1
  20. package/lib/interfaces/client.interface.d.ts +406 -406
  21. package/lib/interfaces/command.interface.d.ts +78 -78
  22. package/lib/interfaces/config.interface.d.ts +151 -151
  23. package/lib/interfaces/device.interface.d.ts +139 -139
  24. package/lib/interfaces/event-properties.interface.d.ts +134 -134
  25. package/lib/interfaces/location.interface.d.ts +187 -187
  26. package/lib/player-client.module.d.ts +9 -9
  27. package/lib/player-client.service.d.ts +640 -640
  28. package/lib/safe-style.pipe.d.ts +23 -23
  29. package/lib/safe-style.pipe.d.ts.map +1 -1
  30. package/lib/version.d.ts +1 -1
  31. package/lib/version.d.ts.map +1 -1
  32. package/package.json +12 -18
  33. package/public-api.d.ts +3 -3
  34. package/schematics/collection.json +15 -15
  35. package/schematics/ng-add/assets/gadget.yaml +54 -54
  36. package/schematics/ng-add/index.d.ts +18 -18
  37. package/schematics/ng-add/index.js +391 -408
  38. package/schematics/ng-add/index.js.map +1 -1
  39. package/schematics/ng-add/schema.d.ts +4 -4
  40. package/schematics/ng-add/schema.js +2 -2
  41. package/schematics/ng-add/schema.json +23 -23
  42. package/schematics/ng-add/templates/index.html +30 -30
  43. package/schematics/ng-add/templates/polyfills.ts +72 -72
  44. package/schematics/ng-add/utils/changeBasePath.js +19 -19
  45. package/schematics/ng-add/utils/yml2xml.js +132 -132
  46. package/esm2020/lib/app-init.service.mjs +0 -110
  47. package/esm2020/lib/interfaces/client.interface.mjs +0 -2
  48. package/esm2020/lib/interfaces/command.interface.mjs +0 -2
  49. package/esm2020/lib/interfaces/config.interface.mjs +0 -50
  50. package/esm2020/lib/interfaces/device.interface.mjs +0 -2
  51. package/esm2020/lib/interfaces/event-properties.interface.mjs +0 -2
  52. package/esm2020/lib/interfaces/location.interface.mjs +0 -2
  53. package/esm2020/lib/player-client.module.mjs +0 -73
  54. package/esm2020/lib/player-client.service.mjs +0 -928
  55. package/esm2020/lib/safe-style.pipe.mjs +0 -40
  56. package/fesm2015/reveldigital-player-client.mjs +0 -1219
  57. package/fesm2015/reveldigital-player-client.mjs.map +0 -1
  58. package/fesm2020/reveldigital-player-client.mjs.map +0 -1
@@ -1,409 +1,392 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.dependencies = exports.ngAdd = void 0;
13
- const tasks_1 = require("@angular-devkit/schematics/tasks");
14
- const schematics_1 = require("@angular-devkit/schematics");
15
- const dependencies_1 = require("@schematics/angular/utility/dependencies");
16
- const core_1 = require("@angular-devkit/core");
17
- const interface_1 = require("@angular-devkit/schematics/src/tree/interface");
18
- const ast_utils_1 = require("@schematics/angular/utility/ast-utils");
19
- const ng_ast_utils_1 = require("@schematics/angular/utility/ng-ast-utils");
20
- const change_1 = require("@schematics/angular/utility/change");
21
- const ts = require("typescript");
22
- /**
23
- * Main schematic rule for adding Revel Digital Player Client to an Angular project.
24
- *
25
- * This schematic performs the following operations:
26
- * - Validates the target project is an Angular application
27
- * - Adds required dependencies to package.json
28
- * - Updates the app module to import PlayerClientModule
29
- * - Adds utility files and assets
30
- * - Configures build scripts for gadget development
31
- * - Optionally sets up GitHub Pages deployment
32
- */
33
- function ngAdd(options) {
34
- return (tree, context) => __awaiter(this, void 0, void 0, function* () {
35
- context.logger.log('info', `🔧 Updating project: ${options.project}`);
36
- const host = createHost(tree);
37
- const { workspace } = yield core_1.workspaces.readWorkspace('/', host);
38
- // Set default project if not specified
39
- if (!options.project) {
40
- options.project = workspace.projects.keys().next().value;
41
- }
42
- // Validate project exists
43
- const project = workspace.projects.get(options.project);
44
- if (!project) {
45
- throw new schematics_1.SchematicsException(`Invalid project name: ${options.project}`);
46
- }
47
- // Validate project is an application
48
- const projectType = project.extensions.projectType === 'application' ? 'app' : 'lib';
49
- if (projectType !== 'app') {
50
- throw new schematics_1.SchematicsException(`Invalid project type: ${projectType}. Project must be an application.`);
51
- }
52
- // Get build configuration
53
- const buildTarget = project.targets.get('build');
54
- if (!buildTarget) {
55
- throw new schematics_1.SchematicsException('Target build not found');
56
- }
57
- const buildOptions = (buildTarget.options || {});
58
- const { main } = buildOptions;
59
- // Schedule package installation
60
- context.addTask(new tasks_1.NodePackageInstallTask());
61
- // Update package.json with new scripts
62
- updatePackageJson(project.root || '', tree, options, context);
63
- return (0, schematics_1.chain)([
64
- addFiles('assets', project.sourceRoot),
65
- addFiles('utils', project.root),
66
- replaceHTML(project.sourceRoot),
67
- addPackageJsonDependencies(),
68
- installPackageJsonDependencies(),
69
- updateAppModule(main),
70
- callDeploySchematic(options.project, options.useGithubPages)
71
- ]);
72
- });
73
- }
74
- exports.ngAdd = ngAdd;
75
- /**
76
- * Adds dependencies required for the schematic.
77
- */
78
- function dependencies(options) {
79
- return (_tree, context) => {
80
- const installTaskId = context.addTask(new tasks_1.NodePackageInstallTask({
81
- packageName: 'angular-cli-ghpages'
82
- }));
83
- context.addTask(new tasks_1.RunSchematicTask('after-dependencies', options), [installTaskId]);
84
- };
85
- }
86
- exports.dependencies = dependencies;
87
- /**
88
- * Conditionally adds GitHub Pages deployment schematic.
89
- */
90
- function callDeploySchematic(project, useGithubPages) {
91
- return (_tree, _context) => {
92
- if (useGithubPages) {
93
- return (0, schematics_1.externalSchematic)('angular-cli-ghpages', 'ng-add', { project: project });
94
- }
95
- return _tree;
96
- };
97
- }
98
- /**
99
- * Replaces HTML templates in the source directory.
100
- */
101
- function replaceHTML(srcRoot) {
102
- return (tree, context) => {
103
- const files = (0, schematics_1.apply)((0, schematics_1.url)('templates'), [
104
- (0, schematics_1.template)({}),
105
- (0, schematics_1.move)(`${srcRoot}`),
106
- ]);
107
- return (0, schematics_1.chain)([(0, schematics_1.mergeWith)(files, interface_1.MergeStrategy.Overwrite)])(tree, context);
108
- };
109
- }
110
- /**
111
- * Adds files from the specified folder to the project.
112
- */
113
- function addFiles(folder, root) {
114
- return (tree, context) => {
115
- context.logger.log('info', `✅️ Adding ${folder}`);
116
- const files = (0, schematics_1.apply)((0, schematics_1.url)(folder), [
117
- (0, schematics_1.template)({}),
118
- (0, schematics_1.move)(`${root}/${folder}`),
119
- ]);
120
- return (0, schematics_1.chain)([(0, schematics_1.mergeWith)(files, interface_1.MergeStrategy.Overwrite)])(tree, context);
121
- };
122
- }
123
- /**
124
- * Adds required dependencies to package.json.
125
- */
126
- function addPackageJsonDependencies() {
127
- return (host, context) => {
128
- const dependencies = [
129
- {
130
- type: dependencies_1.NodeDependencyType.Dev,
131
- name: '@reveldigital/gadget-types',
132
- version: '^1.0.0',
133
- },
134
- {
135
- type: dependencies_1.NodeDependencyType.Dev,
136
- name: 'xmlbuilder2',
137
- version: '^3.1.1',
138
- },
139
- {
140
- type: dependencies_1.NodeDependencyType.Dev,
141
- name: 'node-html-parser',
142
- version: '6.1.12',
143
- },
144
- {
145
- type: dependencies_1.NodeDependencyType.Dev,
146
- name: 'angular-cli-ghpages',
147
- version: '1.0.7',
148
- },
149
- {
150
- type: dependencies_1.NodeDependencyType.Dev,
151
- name: 'git-remote-origin-url',
152
- version: '^4.0.0',
153
- },
154
- {
155
- type: dependencies_1.NodeDependencyType.Dev,
156
- name: 'js-yaml',
157
- version: '^4.1.0',
158
- },
159
- ];
160
- dependencies.forEach(dependency => {
161
- (0, dependencies_1.addPackageJsonDependency)(host, dependency);
162
- context.logger.log('info', `✅️ Added "${dependency.name}" into ${dependency.type}`);
163
- });
164
- return host;
165
- };
166
- }
167
- /**
168
- * Schedules package installation task.
169
- */
170
- function installPackageJsonDependencies() {
171
- return (host, context) => {
172
- context.addTask(new tasks_1.NodePackageInstallTask());
173
- context.logger.log('info', `🔍 Installing packages...`);
174
- return host;
175
- };
176
- }
177
- /**
178
- * Updates the Angular app module to import PlayerClientModule.
179
- */
180
- function updateAppModule(mainPath) {
181
- return (host, context) => {
182
- if (!mainPath) {
183
- context.logger.warn('No main entry point detected. Skipping PlayerClientModule registration.');
184
- return host;
185
- }
186
- context.logger.log('info', '✅️ Configuring Revel Digital Player Client integration');
187
- const modulePath = tryGetAppModulePath(host, mainPath);
188
- if (modulePath) {
189
- context.logger.log('info', `Detected NgModule bootstrap. Updating module at: ${modulePath}`);
190
- ensureImport(host, modulePath, 'PlayerClientModule', '@reveldigital/player-client');
191
- const moduleSource = getTsSourceFile(host, modulePath);
192
- const metadataChanges = (0, ast_utils_1.addSymbolToNgModuleMetadata)(moduleSource, modulePath, 'imports', 'PlayerClientModule');
193
- if (metadataChanges === null || metadataChanges === void 0 ? void 0 : metadataChanges.length) {
194
- const recorder = host.beginUpdate(modulePath);
195
- (0, change_1.applyToUpdateRecorder)(recorder, metadataChanges);
196
- host.commitUpdate(recorder);
197
- }
198
- }
199
- else {
200
- context.logger.log('info', 'Detected standalone bootstrap (no AppModule). Updating main bootstrap configuration.');
201
- updateStandaloneBootstrap(host, mainPath, context);
202
- }
203
- return host;
204
- };
205
- }
206
- /**
207
- * Ensures the specified import exists in the given file.
208
- */
209
- function ensureImport(host, filePath, symbolName, moduleName) {
210
- const moduleSource = getTsSourceFile(host, filePath);
211
- const change = (0, ast_utils_1.insertImport)(moduleSource, filePath, symbolName, moduleName);
212
- if (change) {
213
- const recorder = host.beginUpdate(filePath);
214
- (0, change_1.applyToUpdateRecorder)(recorder, [change]);
215
- host.commitUpdate(recorder);
216
- }
217
- }
218
- /**
219
- * Creates a TypeScript SourceFile from a file path.
220
- */
221
- function getTsSourceFile(host, path) {
222
- const content = host.read(path);
223
- if (!content) {
224
- throw new schematics_1.SchematicsException(`Unable to read TypeScript source: ${path}`);
225
- }
226
- return ts.createSourceFile(path, content.toString(), ts.ScriptTarget.Latest, true);
227
- }
228
- /**
229
- * Attempts to resolve the application module path, returning null if not found.
230
- */
231
- function tryGetAppModulePath(host, mainPath) {
232
- try {
233
- return (0, ng_ast_utils_1.getAppModulePath)(host, mainPath);
234
- }
235
- catch (error) {
236
- if (error instanceof schematics_1.SchematicsException) {
237
- return null;
238
- }
239
- throw error;
240
- }
241
- }
242
- /**
243
- * Updates bootstrap configuration for standalone Angular applications.
244
- */
245
- function updateStandaloneBootstrap(host, mainPath, context) {
246
- ensureImport(host, mainPath, 'PlayerClientModule', '@reveldigital/player-client');
247
- ensureImport(host, mainPath, 'importProvidersFrom', '@angular/core');
248
- const contentBuffer = host.read(mainPath);
249
- if (!contentBuffer) {
250
- throw new schematics_1.SchematicsException(`Unable to read main entry file: ${mainPath}`);
251
- }
252
- const content = contentBuffer.toString();
253
- const sourceFile = ts.createSourceFile(mainPath, content, ts.ScriptTarget.Latest, true);
254
- const bootstrapCall = findBootstrapCall(sourceFile);
255
- if (!bootstrapCall) {
256
- context.logger.warn('bootstrapApplication call not found. Skipping PlayerClientModule provider registration.');
257
- return;
258
- }
259
- if (bootstrapCall.arguments.length === 0) {
260
- context.logger.warn('bootstrapApplication call has no arguments. Skipping PlayerClientModule provider registration.');
261
- return;
262
- }
263
- if (bootstrapCall.arguments.length === 1) {
264
- const recorder = host.beginUpdate(mainPath);
265
- const indentation = calculateIndentation(content, bootstrapCall.getStart(sourceFile));
266
- const insertion = `, {\n${indentation} providers: [importProvidersFrom(PlayerClientModule)]\n${indentation}}`;
267
- recorder.insertLeft(bootstrapCall.end - 1, insertion);
268
- host.commitUpdate(recorder);
269
- return;
270
- }
271
- const optionsArg = bootstrapCall.arguments[1];
272
- if (!ts.isObjectLiteralExpression(optionsArg)) {
273
- context.logger.warn('bootstrapApplication options argument is not an object literal. Skipping PlayerClientModule provider registration.');
274
- return;
275
- }
276
- const providersProperty = optionsArg.properties.find((property) => {
277
- return ts.isPropertyAssignment(property) && isNamedProviders(property.name);
278
- });
279
- if (providersProperty) {
280
- if (!ts.isArrayLiteralExpression(providersProperty.initializer)) {
281
- context.logger.warn('bootstrapApplication providers property is not an array literal. Skipping PlayerClientModule provider registration.');
282
- return;
283
- }
284
- const arrayLiteral = providersProperty.initializer;
285
- const source = arrayLiteral.getSourceFile();
286
- const alreadyConfigured = arrayLiteral.elements.some(element => element.getText(source).includes('PlayerClientModule'));
287
- if (alreadyConfigured) {
288
- return;
289
- }
290
- const recorder = host.beginUpdate(mainPath);
291
- const needsComma = arrayLiteral.elements.length > 0 && !arrayLiteral.elements.hasTrailingComma;
292
- const insertion = `${needsComma ? ',' : ''} importProvidersFrom(PlayerClientModule)`;
293
- recorder.insertLeft(arrayLiteral.end - 1, insertion);
294
- host.commitUpdate(recorder);
295
- return;
296
- }
297
- const recorder = host.beginUpdate(mainPath);
298
- const objectIndentation = calculateIndentation(content, optionsArg.getStart(sourceFile));
299
- const propertyIndentation = `${objectIndentation} `;
300
- const prefix = optionsArg.properties.length > 0 ? ',' : '';
301
- const insertion = `${prefix}\n${propertyIndentation}providers: [importProvidersFrom(PlayerClientModule)]\n${objectIndentation}`;
302
- recorder.insertLeft(optionsArg.end - 1, insertion);
303
- host.commitUpdate(recorder);
304
- }
305
- /**
306
- * Finds the bootstrapApplication call expression within the provided source file.
307
- */
308
- function findBootstrapCall(sourceFile) {
309
- let found;
310
- const visit = (node) => {
311
- if (ts.isCallExpression(node)) {
312
- const expression = node.expression;
313
- if (ts.isIdentifier(expression) && expression.text === 'bootstrapApplication') {
314
- found = node;
315
- return;
316
- }
317
- }
318
- ts.forEachChild(node, visit);
319
- };
320
- ts.forEachChild(sourceFile, visit);
321
- return found;
322
- }
323
- /**
324
- * Determines if a property name corresponds to the "providers" key.
325
- */
326
- function isNamedProviders(name) {
327
- return (ts.isIdentifier(name) || ts.isStringLiteral(name)) && name.text === 'providers';
328
- }
329
- /**
330
- * Calculates the indentation for the line containing the specified position.
331
- */
332
- function calculateIndentation(content, position) {
333
- const lineStart = content.lastIndexOf('\n', position);
334
- if (lineStart === -1) {
335
- return '';
336
- }
337
- const line = content.slice(lineStart + 1, position);
338
- const match = line.match(/^[\t ]*/);
339
- return match ? match[0] : '';
340
- }
341
- /**
342
- * Updates the scripts section in package.json with gadget-specific build commands.
343
- */
344
- function updateScripts(path, config, tree, _options, _context) {
345
- if (!config.scripts) {
346
- config.scripts = {};
347
- }
348
- config.scripts['build:gadget'] = 'npm run change-path && ng build && node utils/yml2xml.js src/assets/gadget.yaml dist';
349
- config.scripts['deploy:gadget'] = 'npm run build:gadget && ng deploy --no-build';
350
- config.scripts['change-path'] = 'node utils/changeBasePath.js';
351
- }
352
- /**
353
- * Updates package.json with new scripts and configurations.
354
- */
355
- function updatePackageJson(path, tree, options, context) {
356
- const config = loadPackageJson(tree);
357
- updateScripts(path, config, tree, options, context);
358
- savePackageJson(config, tree);
359
- }
360
- /**
361
- * Saves the updated package.json configuration to the tree.
362
- */
363
- function savePackageJson(config, tree) {
364
- const newContentAsString = JSON.stringify(config, null, 2) || '';
365
- tree.overwrite('package.json', newContentAsString);
366
- }
367
- /**
368
- * Loads and parses the package.json file from the tree.
369
- */
370
- function loadPackageJson(tree) {
371
- const pkg = tree.read('package.json');
372
- if (pkg === null) {
373
- throw new Error('could not read package.json');
374
- }
375
- const contentAsString = pkg.toString('UTF-8');
376
- return JSON.parse(contentAsString);
377
- }
378
- /**
379
- * Creates a workspace host for reading and writing files in the schematic tree.
380
- */
381
- function createHost(tree) {
382
- return {
383
- readFile(path) {
384
- return __awaiter(this, void 0, void 0, function* () {
385
- const data = tree.read(path);
386
- if (!data) {
387
- throw new schematics_1.SchematicsException('File not found.');
388
- }
389
- return core_1.virtualFs.fileBufferToString(data.buffer);
390
- });
391
- },
392
- writeFile(path, data) {
393
- return __awaiter(this, void 0, void 0, function* () {
394
- return tree.overwrite(path, data);
395
- });
396
- },
397
- isDirectory(path) {
398
- return __awaiter(this, void 0, void 0, function* () {
399
- return !tree.exists(path) && tree.getDir(path).subfiles.length > 0;
400
- });
401
- },
402
- isFile(path) {
403
- return __awaiter(this, void 0, void 0, function* () {
404
- return tree.exists(path);
405
- });
406
- },
407
- };
408
- }
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dependencies = exports.ngAdd = void 0;
4
+ const tasks_1 = require("@angular-devkit/schematics/tasks");
5
+ const schematics_1 = require("@angular-devkit/schematics");
6
+ const dependencies_1 = require("@schematics/angular/utility/dependencies");
7
+ const core_1 = require("@angular-devkit/core");
8
+ const schematics_2 = require("@angular-devkit/schematics");
9
+ const ast_utils_1 = require("@schematics/angular/utility/ast-utils");
10
+ const ng_ast_utils_1 = require("@schematics/angular/utility/ng-ast-utils");
11
+ const change_1 = require("@schematics/angular/utility/change");
12
+ const ts = require("typescript");
13
+ /**
14
+ * Main schematic rule for adding Revel Digital Player Client to an Angular project.
15
+ *
16
+ * This schematic performs the following operations:
17
+ * - Validates the target project is an Angular application
18
+ * - Adds required dependencies to package.json
19
+ * - Updates the app module to import PlayerClientModule
20
+ * - Adds utility files and assets
21
+ * - Configures build scripts for gadget development
22
+ * - Optionally sets up GitHub Pages deployment
23
+ */
24
+ function ngAdd(options) {
25
+ return async (tree, context) => {
26
+ context.logger.log('info', `🔧 Updating project: ${options.project}`);
27
+ const host = createHost(tree);
28
+ const { workspace } = await core_1.workspaces.readWorkspace('/', host);
29
+ // Set default project if not specified
30
+ if (!options.project) {
31
+ options.project = workspace.projects.keys().next().value;
32
+ }
33
+ // Validate project exists
34
+ const project = workspace.projects.get(options.project);
35
+ if (!project) {
36
+ throw new schematics_1.SchematicsException(`Invalid project name: ${options.project}`);
37
+ }
38
+ // Validate project is an application
39
+ const projectType = project.extensions.projectType === 'application' ? 'app' : 'lib';
40
+ if (projectType !== 'app') {
41
+ throw new schematics_1.SchematicsException(`Invalid project type: ${projectType}. Project must be an application.`);
42
+ }
43
+ // Get build configuration
44
+ const buildTarget = project.targets.get('build');
45
+ if (!buildTarget) {
46
+ throw new schematics_1.SchematicsException('Target build not found');
47
+ }
48
+ const buildOptions = (buildTarget.options || {});
49
+ const main = buildOptions.browser || buildOptions.main;
50
+ // Schedule package installation
51
+ context.addTask(new tasks_1.NodePackageInstallTask());
52
+ // Update package.json with new scripts
53
+ updatePackageJson(project.root || '', tree, options, context);
54
+ return (0, schematics_1.chain)([
55
+ addFiles('assets', project.sourceRoot),
56
+ addFiles('utils', project.root),
57
+ replaceHTML(project.sourceRoot),
58
+ addPackageJsonDependencies(),
59
+ installPackageJsonDependencies(),
60
+ updateAppModule(main),
61
+ callDeploySchematic(options.project, options.useGithubPages)
62
+ ]);
63
+ };
64
+ }
65
+ exports.ngAdd = ngAdd;
66
+ /**
67
+ * Adds dependencies required for the schematic.
68
+ */
69
+ function dependencies(options) {
70
+ return (_tree, context) => {
71
+ const installTaskId = context.addTask(new tasks_1.NodePackageInstallTask({
72
+ packageName: 'angular-cli-ghpages'
73
+ }));
74
+ context.addTask(new tasks_1.RunSchematicTask('after-dependencies', options), [installTaskId]);
75
+ };
76
+ }
77
+ exports.dependencies = dependencies;
78
+ /**
79
+ * Conditionally adds GitHub Pages deployment schematic.
80
+ */
81
+ function callDeploySchematic(project, useGithubPages) {
82
+ return (_tree, _context) => {
83
+ if (useGithubPages) {
84
+ return (0, schematics_1.externalSchematic)('angular-cli-ghpages', 'ng-add', { project: project });
85
+ }
86
+ return _tree;
87
+ };
88
+ }
89
+ /**
90
+ * Replaces HTML templates in the source directory.
91
+ */
92
+ function replaceHTML(srcRoot) {
93
+ return (tree, context) => {
94
+ const files = (0, schematics_1.apply)((0, schematics_1.url)('templates'), [
95
+ (0, schematics_1.template)({}),
96
+ (0, schematics_1.move)(`${srcRoot}`),
97
+ ]);
98
+ return (0, schematics_1.chain)([(0, schematics_1.mergeWith)(files, schematics_2.MergeStrategy.Overwrite)])(tree, context);
99
+ };
100
+ }
101
+ /**
102
+ * Adds files from the specified folder to the project.
103
+ */
104
+ function addFiles(folder, root) {
105
+ return (tree, context) => {
106
+ context.logger.log('info', `✅️ Adding ${folder}`);
107
+ const files = (0, schematics_1.apply)((0, schematics_1.url)(folder), [
108
+ (0, schematics_1.template)({}),
109
+ (0, schematics_1.move)(`${root}/${folder}`),
110
+ ]);
111
+ return (0, schematics_1.chain)([(0, schematics_1.mergeWith)(files, schematics_2.MergeStrategy.Overwrite)])(tree, context);
112
+ };
113
+ }
114
+ /**
115
+ * Adds required dependencies to package.json.
116
+ */
117
+ function addPackageJsonDependencies() {
118
+ return (host, context) => {
119
+ const dependencies = [
120
+ {
121
+ type: dependencies_1.NodeDependencyType.Dev,
122
+ name: '@reveldigital/gadget-types',
123
+ version: '^1.0.0',
124
+ },
125
+ {
126
+ type: dependencies_1.NodeDependencyType.Dev,
127
+ name: 'xmlbuilder2',
128
+ version: '^3.1.1',
129
+ },
130
+ {
131
+ type: dependencies_1.NodeDependencyType.Dev,
132
+ name: 'node-html-parser',
133
+ version: '6.1.12',
134
+ },
135
+ {
136
+ type: dependencies_1.NodeDependencyType.Dev,
137
+ name: 'angular-cli-ghpages',
138
+ version: '^2.0.0',
139
+ },
140
+ {
141
+ type: dependencies_1.NodeDependencyType.Dev,
142
+ name: 'git-remote-origin-url',
143
+ version: '^4.0.0',
144
+ },
145
+ {
146
+ type: dependencies_1.NodeDependencyType.Dev,
147
+ name: 'js-yaml',
148
+ version: '^4.1.0',
149
+ },
150
+ ];
151
+ dependencies.forEach(dependency => {
152
+ (0, dependencies_1.addPackageJsonDependency)(host, dependency);
153
+ context.logger.log('info', `✅️ Added "${dependency.name}" into ${dependency.type}`);
154
+ });
155
+ return host;
156
+ };
157
+ }
158
+ /**
159
+ * Schedules package installation task.
160
+ */
161
+ function installPackageJsonDependencies() {
162
+ return (host, context) => {
163
+ context.addTask(new tasks_1.NodePackageInstallTask());
164
+ context.logger.log('info', `🔍 Installing packages...`);
165
+ return host;
166
+ };
167
+ }
168
+ /**
169
+ * Updates the Angular app module to import PlayerClientModule.
170
+ */
171
+ function updateAppModule(mainPath) {
172
+ return (host, context) => {
173
+ if (!mainPath) {
174
+ context.logger.warn('No main entry point detected. Skipping PlayerClientModule registration.');
175
+ return host;
176
+ }
177
+ context.logger.log('info', '✅️ Configuring Revel Digital Player Client integration');
178
+ const modulePath = tryGetAppModulePath(host, mainPath);
179
+ if (modulePath) {
180
+ context.logger.log('info', `Detected NgModule bootstrap. Updating module at: ${modulePath}`);
181
+ ensureImport(host, modulePath, 'PlayerClientModule', '@reveldigital/player-client');
182
+ const moduleSource = getTsSourceFile(host, modulePath);
183
+ const metadataChanges = (0, ast_utils_1.addSymbolToNgModuleMetadata)(moduleSource, modulePath, 'imports', 'PlayerClientModule');
184
+ if (metadataChanges?.length) {
185
+ const recorder = host.beginUpdate(modulePath);
186
+ (0, change_1.applyToUpdateRecorder)(recorder, metadataChanges);
187
+ host.commitUpdate(recorder);
188
+ }
189
+ }
190
+ else {
191
+ context.logger.log('info', 'Detected standalone bootstrap (no AppModule). Updating main bootstrap configuration.');
192
+ updateStandaloneBootstrap(host, mainPath, context);
193
+ }
194
+ return host;
195
+ };
196
+ }
197
+ /**
198
+ * Ensures the specified import exists in the given file.
199
+ */
200
+ function ensureImport(host, filePath, symbolName, moduleName) {
201
+ const moduleSource = getTsSourceFile(host, filePath);
202
+ const change = (0, ast_utils_1.insertImport)(moduleSource, filePath, symbolName, moduleName);
203
+ if (change) {
204
+ const recorder = host.beginUpdate(filePath);
205
+ (0, change_1.applyToUpdateRecorder)(recorder, [change]);
206
+ host.commitUpdate(recorder);
207
+ }
208
+ }
209
+ /**
210
+ * Creates a TypeScript SourceFile from a file path.
211
+ */
212
+ function getTsSourceFile(host, path) {
213
+ const content = host.read(path);
214
+ if (!content) {
215
+ throw new schematics_1.SchematicsException(`Unable to read TypeScript source: ${path}`);
216
+ }
217
+ return ts.createSourceFile(path, content.toString(), ts.ScriptTarget.Latest, true);
218
+ }
219
+ /**
220
+ * Attempts to resolve the application module path, returning null if not found.
221
+ */
222
+ function tryGetAppModulePath(host, mainPath) {
223
+ try {
224
+ return (0, ng_ast_utils_1.getAppModulePath)(host, mainPath);
225
+ }
226
+ catch (error) {
227
+ if (error instanceof schematics_1.SchematicsException) {
228
+ return null;
229
+ }
230
+ throw error;
231
+ }
232
+ }
233
+ /**
234
+ * Updates bootstrap configuration for standalone Angular applications.
235
+ */
236
+ function updateStandaloneBootstrap(host, mainPath, context) {
237
+ ensureImport(host, mainPath, 'PlayerClientModule', '@reveldigital/player-client');
238
+ ensureImport(host, mainPath, 'importProvidersFrom', '@angular/core');
239
+ const contentBuffer = host.read(mainPath);
240
+ if (!contentBuffer) {
241
+ throw new schematics_1.SchematicsException(`Unable to read main entry file: ${mainPath}`);
242
+ }
243
+ const content = contentBuffer.toString();
244
+ const sourceFile = ts.createSourceFile(mainPath, content, ts.ScriptTarget.Latest, true);
245
+ const bootstrapCall = findBootstrapCall(sourceFile);
246
+ if (!bootstrapCall) {
247
+ context.logger.warn('bootstrapApplication call not found. Skipping PlayerClientModule provider registration.');
248
+ return;
249
+ }
250
+ if (bootstrapCall.arguments.length === 0) {
251
+ context.logger.warn('bootstrapApplication call has no arguments. Skipping PlayerClientModule provider registration.');
252
+ return;
253
+ }
254
+ if (bootstrapCall.arguments.length === 1) {
255
+ const recorder = host.beginUpdate(mainPath);
256
+ const indentation = calculateIndentation(content, bootstrapCall.getStart(sourceFile));
257
+ const insertion = `, {\n${indentation} providers: [importProvidersFrom(PlayerClientModule)]\n${indentation}}`;
258
+ recorder.insertLeft(bootstrapCall.end - 1, insertion);
259
+ host.commitUpdate(recorder);
260
+ return;
261
+ }
262
+ const optionsArg = bootstrapCall.arguments[1];
263
+ if (!ts.isObjectLiteralExpression(optionsArg)) {
264
+ context.logger.warn('bootstrapApplication options argument is not an object literal. Skipping PlayerClientModule provider registration.');
265
+ return;
266
+ }
267
+ const providersProperty = optionsArg.properties.find((property) => {
268
+ return ts.isPropertyAssignment(property) && isNamedProviders(property.name);
269
+ });
270
+ if (providersProperty) {
271
+ if (!ts.isArrayLiteralExpression(providersProperty.initializer)) {
272
+ context.logger.warn('bootstrapApplication providers property is not an array literal. Skipping PlayerClientModule provider registration.');
273
+ return;
274
+ }
275
+ const arrayLiteral = providersProperty.initializer;
276
+ const source = arrayLiteral.getSourceFile();
277
+ const alreadyConfigured = arrayLiteral.elements.some(element => element.getText(source).includes('PlayerClientModule'));
278
+ if (alreadyConfigured) {
279
+ return;
280
+ }
281
+ const recorder = host.beginUpdate(mainPath);
282
+ const needsComma = arrayLiteral.elements.length > 0 && !arrayLiteral.elements.hasTrailingComma;
283
+ const insertion = `${needsComma ? ',' : ''} importProvidersFrom(PlayerClientModule)`;
284
+ recorder.insertLeft(arrayLiteral.end - 1, insertion);
285
+ host.commitUpdate(recorder);
286
+ return;
287
+ }
288
+ const recorder = host.beginUpdate(mainPath);
289
+ const objectIndentation = calculateIndentation(content, optionsArg.getStart(sourceFile));
290
+ const propertyIndentation = `${objectIndentation} `;
291
+ const prefix = optionsArg.properties.length > 0 ? ',' : '';
292
+ const insertion = `${prefix}\n${propertyIndentation}providers: [importProvidersFrom(PlayerClientModule)]\n${objectIndentation}`;
293
+ recorder.insertLeft(optionsArg.end - 1, insertion);
294
+ host.commitUpdate(recorder);
295
+ }
296
+ /**
297
+ * Finds the bootstrapApplication call expression within the provided source file.
298
+ */
299
+ function findBootstrapCall(sourceFile) {
300
+ let found;
301
+ const visit = (node) => {
302
+ if (ts.isCallExpression(node)) {
303
+ const expression = node.expression;
304
+ if (ts.isIdentifier(expression) && expression.text === 'bootstrapApplication') {
305
+ found = node;
306
+ return;
307
+ }
308
+ }
309
+ ts.forEachChild(node, visit);
310
+ };
311
+ ts.forEachChild(sourceFile, visit);
312
+ return found;
313
+ }
314
+ /**
315
+ * Determines if a property name corresponds to the "providers" key.
316
+ */
317
+ function isNamedProviders(name) {
318
+ return (ts.isIdentifier(name) || ts.isStringLiteral(name)) && name.text === 'providers';
319
+ }
320
+ /**
321
+ * Calculates the indentation for the line containing the specified position.
322
+ */
323
+ function calculateIndentation(content, position) {
324
+ const lineStart = content.lastIndexOf('\n', position);
325
+ if (lineStart === -1) {
326
+ return '';
327
+ }
328
+ const line = content.slice(lineStart + 1, position);
329
+ const match = line.match(/^[\t ]*/);
330
+ return match ? match[0] : '';
331
+ }
332
+ /**
333
+ * Updates the scripts section in package.json with gadget-specific build commands.
334
+ */
335
+ function updateScripts(path, config, tree, _options, _context) {
336
+ if (!config.scripts) {
337
+ config.scripts = {};
338
+ }
339
+ config.scripts['build:gadget'] = 'npm run change-path && ng build && node utils/yml2xml.js src/assets/gadget.yaml dist';
340
+ config.scripts['deploy:gadget'] = 'npm run build:gadget && ng deploy --no-build';
341
+ config.scripts['change-path'] = 'node utils/changeBasePath.js';
342
+ }
343
+ /**
344
+ * Updates package.json with new scripts and configurations.
345
+ */
346
+ function updatePackageJson(path, tree, options, context) {
347
+ const config = loadPackageJson(tree);
348
+ updateScripts(path, config, tree, options, context);
349
+ savePackageJson(config, tree);
350
+ }
351
+ /**
352
+ * Saves the updated package.json configuration to the tree.
353
+ */
354
+ function savePackageJson(config, tree) {
355
+ const newContentAsString = JSON.stringify(config, null, 2) || '';
356
+ tree.overwrite('package.json', newContentAsString);
357
+ }
358
+ /**
359
+ * Loads and parses the package.json file from the tree.
360
+ */
361
+ function loadPackageJson(tree) {
362
+ const pkg = tree.read('package.json');
363
+ if (pkg === null) {
364
+ throw new Error('could not read package.json');
365
+ }
366
+ const contentAsString = pkg.toString('utf-8');
367
+ return JSON.parse(contentAsString);
368
+ }
369
+ /**
370
+ * Creates a workspace host for reading and writing files in the schematic tree.
371
+ */
372
+ function createHost(tree) {
373
+ return {
374
+ async readFile(path) {
375
+ const data = tree.read(path);
376
+ if (!data) {
377
+ throw new schematics_1.SchematicsException('File not found.');
378
+ }
379
+ return core_1.virtualFs.fileBufferToString(data.buffer);
380
+ },
381
+ async writeFile(path, data) {
382
+ return tree.overwrite(path, data);
383
+ },
384
+ async isDirectory(path) {
385
+ return !tree.exists(path) && tree.getDir(path).subfiles.length > 0;
386
+ },
387
+ async isFile(path) {
388
+ return tree.exists(path);
389
+ },
390
+ };
391
+ }
409
392
  //# sourceMappingURL=index.js.map