@luzmo/ngx-embed
Version:
This is an Angular library for embedding [Luzmo](https://luzmo.com) dashboards in your Angular application.
151 lines • 7.72 kB
JavaScript
import { execSync } from 'node:child_process';
import { SchematicsException, chain } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { addRootImport } from '@schematics/angular/utility';
function getLatestStableVersion(packageName, context) {
try {
// Get all versions and filter for stable ones
const command = `npm view ${packageName} versions --json`;
const versionsOutput = execSync(command, { encoding: 'utf8' }).trim();
const versions = JSON.parse(versionsOutput);
// Filter out pre-release versions (containing alpha, beta, rc, etc.)
const stableVersions = versions.filter((version) => {
const isPrerelease = /-(alpha|beta|rc|pre|dev|snapshot|canary)/i.test(version);
return !isPrerelease;
});
if (stableVersions.length === 0) {
context.logger.warn('⚠️ No stable versions found, using fallback');
return '7.0.0';
}
// Get the latest stable version (last in the sorted array)
const latestStable = stableVersions.at(-1);
context.logger.info(`✅ Found latest stable version: ${latestStable}`);
return latestStable;
}
catch (_a) {
context.logger.warn('⚠️ Could not fetch latest stable version from npm registry');
return '7.0.0'; // fallback to stable version
}
}
function addPackageToPackageJson() {
return (tree, context) => {
const packageJsonPath = '/package.json';
if (!tree.exists(packageJsonPath)) {
throw new SchematicsException('Could not find package.json');
}
const packageJsonContent = tree.read(packageJsonPath);
if (!packageJsonContent) {
throw new SchematicsException('Could not read package.json');
}
const packageJson = JSON.parse(packageJsonContent.toString());
if (!packageJson.dependencies) {
packageJson.dependencies = {};
}
// Add the package if it's not already present
if (!packageJson.dependencies['@luzmo/ngx-embed']) {
context.logger.info('🔍 Fetching latest stable version of @luzmo/ngx-embed...');
const latestVersion = getLatestStableVersion('@luzmo/ngx-embed', context);
packageJson.dependencies['@luzmo/ngx-embed'] = `^${latestVersion}`;
context.logger.info(`📦 Adding @luzmo/ngx-embed@${latestVersion} to package.json`);
tree.overwrite(packageJsonPath, JSON.stringify(packageJson, null, 2));
}
return tree;
};
}
function getAvailableProjectsSync(tree) {
try {
const workspaceContent = tree.read('/angular.json') || tree.read('/workspace.json');
if (!workspaceContent) {
throw new SchematicsException('Could not find workspace configuration file');
}
const workspace = JSON.parse(workspaceContent.toString());
return Object.entries(workspace.projects || {})
.filter(([, project]) => project.projectType === 'application')
.map(([name]) => name);
}
catch (_a) {
throw new SchematicsException('Could not read workspace configuration');
}
}
function selectProjectInteractively(tree, context, options) {
if (options.project) {
// Project was specified, validate it exists
const projectsToValidate = getAvailableProjectsSync(tree);
if (!projectsToValidate.includes(options.project)) {
throw new SchematicsException(`Project "${options.project}" not found. Available projects: ${projectsToValidate.join(', ')}`);
}
return options.project;
}
// No project specified, check available projects
const availableProjects = getAvailableProjectsSync(tree);
if (availableProjects.length === 0) {
throw new SchematicsException('No application projects found in workspace');
}
if (availableProjects.length === 1) {
context.logger.info(`📦 Using the only available project: ${availableProjects[0]}`);
return availableProjects[0];
}
// Multiple projects found - create an interactive selection
context.logger.info('\n🎯 Multiple projects found! Please select one:');
availableProjects.forEach((project, index) => {
context.logger.info(` ${index + 1}. ${project}`);
});
// Create formatted selection interface
const projectSelections = availableProjects
.map((project, index) => `│ ${String(index + 1).padStart(2)}. ng add @luzmo/ngx-embed --project=${project.padEnd(30)} │`)
.join('\n');
throw new SchematicsException('\n'
+ '╭─ Multiple Projects Detected ────────────────────────────────────╮\n'
+ '│ │\n'
+ '│ Please specify which project to use: │\n'
+ '│ │\n'
+ projectSelections
+ '\n'
+ '│ │\n'
+ '╰─────────────────────────────────────────────────────────────────╯');
}
function addEntityToProject(options) {
return (tree, context) => {
// Available entities for validation (CLI will prompt based on schema.json)
const availableEntities = [
'NgxLuzmoDashboardModule',
'NgxLuzmoDashboardComponent',
'NgxLuzmoVizItemComponent',
'NgxLuzmoIQChatComponent',
'NgxLuzmoIQAnswerComponent'
];
// Debug: Log what we received
context.logger.info(`🔍 Debug: Received options - entity: ${options.entity}, project: ${options.project}`);
const selectedEntity = options.entity; // CLI ensures this is provided via schema
// Handle project selection interactively
const validatedProject = selectProjectInteractively(tree, context, options);
// Only validate if entity is actually invalid (shouldn't happen with proper schema)
if (!availableEntities.includes(selectedEntity)) {
throw new SchematicsException(`Entity "${selectedEntity}" is not available. Available entities: ${availableEntities.join(', ')}`);
}
context.logger.info(`✅ Adding ${selectedEntity} to project "${validatedProject}"`);
// Use Angular's built-in utility for adding imports
// This handles both NgModule and standalone apps automatically
return addRootImport(validatedProject, ({ code, external }) => {
if (selectedEntity === 'NgxLuzmoDashboardModule') {
// For modules, add as root import
context.logger.info('📦 Adding module to your app imports');
return code `${external(selectedEntity, '@luzmo/ngx-embed')}`;
}
// For standalone components, just add the import (user will use it in templates)
context.logger.info(`📦 Import added for ${selectedEntity}. You can now use it in your components.`);
return code `${external(selectedEntity, '@luzmo/ngx-embed')}`;
});
};
}
export function ngAdd(options) {
return chain([
addPackageToPackageJson(),
(tree, context) => {
context.addTask(new NodePackageInstallTask());
return tree;
},
addEntityToProject(options)
]);
}
//# sourceMappingURL=index.js.map