ng-apexcharts
Version:
An angular implementation of ApexCharts
198 lines (197 loc) • 8.41 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.readJsonInTree = readJsonInTree;
exports.updateJsonInTree = updateJsonInTree;
exports.getProjectFromWorkspace = getProjectFromWorkspace;
exports.addPackageToPackageJson = addPackageToPackageJson;
exports.getProjectTargetOptions = getProjectTargetOptions;
exports.getProjectMainFile = getProjectMainFile;
exports.hasNgModuleImport = hasNgModuleImport;
exports.addModuleImportToRootModule = addModuleImportToRootModule;
const schematics_1 = require("@angular-devkit/schematics");
const change_1 = require("@schematics/angular/utility/change");
const ast_utils_1 = require("@schematics/angular/utility/ast-utils");
const ng_ast_utils_1 = require("@schematics/angular/utility/ng-ast-utils");
const stripJsonComments = require("strip-json-comments");
const ts = require("@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript");
function readJsonInTree(host, path) {
if (!host.exists(path)) {
throw new Error(`Cannot find ${path}`);
}
const contents = stripJsonComments(host.read(path).toString("utf-8"));
try {
return JSON.parse(contents);
}
catch (e) {
throw new Error(`Cannot parse ${path}: ${e instanceof Error ? e.message : ""}`);
}
}
function updateJsonInTree(path, callback) {
return (host, context) => {
if (!host.exists(path)) {
host.create(path, serializeJson(callback({}, context)));
return host;
}
host.overwrite(path, serializeJson(callback(readJsonInTree(host, path), context)));
return host;
};
}
function serializeJson(json) {
return `${JSON.stringify(json, null, 2)}\n`;
}
function getProjectFromWorkspace(workspace, projectName) {
if (!projectName) {
// TODO(crisbeto): some schematics APIs have the project name as optional so for now it's
// simpler to allow undefined and checking it at runtime. Eventually we should clean this up.
throw new schematics_1.SchematicsException("Project name is required.");
}
const project = workspace.projects.get(projectName);
if (!project) {
throw new schematics_1.SchematicsException(`Could not find project in workspace: ${projectName}`);
}
return project;
}
function addPackageToPackageJson(host, pkg, version) {
if (host.exists("package.json")) {
const sourceText = host.read("package.json").toString("utf-8");
const json = JSON.parse(sourceText);
if (!json.dependencies) {
json.dependencies = {};
}
if (!json.dependencies[pkg]) {
json.dependencies[pkg] = version;
json.dependencies = sortObjectByKeys(json.dependencies);
}
host.overwrite("package.json", JSON.stringify(json, null, 2));
}
return host;
}
function sortObjectByKeys(obj) {
return Object.keys(obj)
.sort()
.reduce((result, key) => (result[key] = obj[key]) && result, {});
}
function getProjectTargetOptions(project, buildTarget) {
var _a, _b;
if ((_b = (_a = project === null || project === void 0 ? void 0 : project.targets) === null || _a === void 0 ? void 0 : _a.get(buildTarget)) === null || _b === void 0 ? void 0 : _b.options) {
return project.targets.get(buildTarget).options;
}
throw new Error(`Cannot determine project target configuration for: ${buildTarget}.`);
}
function getProjectMainFile(project) {
const buildOptions = getProjectTargetOptions(project, "build");
if (!buildOptions) {
throw new schematics_1.SchematicsException("Could not find the project main file inside of the " +
`workspace config (${project.sourceRoot})`);
}
// `browser` is for the `@angular-devkit/build-angular:application` builder while
// `main` is for the `@angular-devkit/build-angular:browser` builder.
const mainPath = (buildOptions["browser"] || buildOptions["main"]);
if (!mainPath) {
throw new schematics_1.SchematicsException("Could not find the project main file inside of the " +
`workspace config (${project.sourceRoot})`);
}
return mainPath;
}
/**
* Whether the Angular module in the given path imports the specified module class name.
*/
function hasNgModuleImport(tree, modulePath, className) {
const moduleFileContent = tree.read(modulePath);
if (!moduleFileContent) {
throw new schematics_1.SchematicsException(`Could not read Angular module file: ${modulePath}`);
}
const parsedFile = ts.createSourceFile(modulePath, moduleFileContent.toString(), ts.ScriptTarget.Latest, true);
const ngModuleMetadata = findNgModuleMetadata(parsedFile);
if (!ngModuleMetadata) {
throw new schematics_1.SchematicsException(`Could not find NgModule declaration inside: "${modulePath}"`);
}
for (const property of ngModuleMetadata.properties) {
if (!ts.isPropertyAssignment(property) ||
property.name.getText() !== "imports" ||
!ts.isArrayLiteralExpression(property.initializer)) {
continue;
}
if (property.initializer.elements.some((element) => element.getText() === className)) {
return true;
}
}
return false;
}
/**
* Finds a NgModule declaration within the specified TypeScript node and returns the
* corresponding metadata for it. This function searches breadth first because
* NgModule's are usually not nested within other expressions or declarations.
*/
function findNgModuleMetadata(rootNode) {
// Add immediate child nodes of the root node to the queue.
const nodeQueue = [...rootNode.getChildren()];
while (nodeQueue.length) {
const node = nodeQueue.shift();
if (ts.isDecorator(node) &&
ts.isCallExpression(node.expression) &&
isNgModuleCallExpression(node.expression)) {
return node.expression.arguments[0];
}
else {
nodeQueue.push(...node.getChildren());
}
}
return null;
}
/** Whether the specified call expression is referring to a NgModule definition. */
function isNgModuleCallExpression(callExpression) {
if (!callExpression.arguments.length ||
!ts.isObjectLiteralExpression(callExpression.arguments[0])) {
return false;
}
// The `NgModule` call expression name is never referring to a `PrivateIdentifier`.
const decoratorIdentifier = resolveIdentifierOfExpression(callExpression.expression);
return decoratorIdentifier ? decoratorIdentifier.text === "NgModule" : false;
}
/**
* Resolves the last identifier that is part of the given expression. This helps resolving
* identifiers of nested property access expressions (e.g. myNamespace.core.NgModule).
*/
function resolveIdentifierOfExpression(expression) {
if (ts.isIdentifier(expression)) {
return expression;
}
else if (ts.isPropertyAccessExpression(expression) &&
ts.isIdentifier(expression.name)) {
return expression.name;
}
return null;
}
function addModuleImportToRootModule(host, moduleName, src, project) {
const modulePath = (0, ng_ast_utils_1.getAppModulePath)(host, getProjectMainFile(project));
addModuleImportToModule(host, modulePath, moduleName, src);
}
/**
* Import and add module to specific module path.
* @param host the tree we are updating
* @param modulePath src location of the module to import
* @param moduleName name of module to import
* @param src src location to import
*/
function addModuleImportToModule(host, modulePath, moduleName, src) {
const moduleSource = parseSourceFile(host, modulePath);
if (!moduleSource) {
throw new schematics_1.SchematicsException(`Module not found: ${modulePath}`);
}
const changes = (0, ast_utils_1.addImportToModule)(moduleSource, modulePath, moduleName, src);
const recorder = host.beginUpdate(modulePath);
changes.forEach((change) => {
if (change instanceof change_1.InsertChange) {
recorder.insertLeft(change.pos, change.toAdd);
}
});
host.commitUpdate(recorder);
}
function parseSourceFile(host, path) {
const buffer = host.read(path);
if (!buffer) {
throw new schematics_1.SchematicsException(`Could not find file for path: ${path}`);
}
return ts.createSourceFile(path, buffer.toString(), ts.ScriptTarget.Latest, true);
}