Example #1
0
  return (host: Tree, context: SchematicContext) => {
    context.logger.debug('Updating appmodule');

    // find app module
    const projectTargets = getProjectTargets(host, options.project);
    if (!projectTargets.build) {
      throw targetBuildNotFoundError();
    }

    const mainPath = projectTargets.build.options.main;
    const modulePath = getAppModulePath(host, mainPath);
    context.logger.debug(`module path: ${modulePath}`);

    // add import
    let moduleSource = getTsSourceFile(host, modulePath);
    let importModule = 'ServiceWorkerModule';
    let importPath = '@angular/service-worker';
    if (!isImported(moduleSource, importModule, importPath)) {
      const change = insertImport
      (moduleSource, modulePath, importModule, importPath);
      if (change) {
        const recorder = host.beginUpdate(modulePath);
        recorder.insertLeft((change as InsertChange).pos, (change as InsertChange).toAdd);
        host.commitUpdate(recorder);
      }
    }

    // add import for environments
    // import { environment } from '../environments/environment';
    moduleSource = getTsSourceFile(host, modulePath);
    importModule = 'environment';
    // TODO: dynamically find environments relative path
    importPath = '../environments/environment';
    if (!isImported(moduleSource, importModule, importPath)) {
      const change = insertImport
      (moduleSource, modulePath, importModule, importPath);
      if (change) {
        const recorder = host.beginUpdate(modulePath);
        recorder.insertLeft((change as InsertChange).pos, (change as InsertChange).toAdd);
        host.commitUpdate(recorder);
      }
    }

    // register SW in app module
    const importText =
      `ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production })`;
    moduleSource = getTsSourceFile(host, modulePath);
    const metadataChanges = addSymbolToNgModuleMetadata(
      moduleSource, modulePath, 'imports', importText);
    if (metadataChanges) {
      const recorder = host.beginUpdate(modulePath);
      metadataChanges.forEach((change: InsertChange) => {
        recorder.insertRight(change.pos, change.toAdd);
      });
      host.commitUpdate(recorder);
    }

    return host;
  };
Example #2
0
File: index.ts Project: iwe7/devkit
  return (host: Tree) => {
    if (options.skipImport || !options.module) {
      return host;
    }

    const modulePath = options.module;
    const text = host.read(modulePath);
    if (text === null) {
      throw new SchematicsException(`File ${modulePath} does not exist.`);
    }
    const sourceText = text.toString('utf-8');
    const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);

    const componentPath = `/${options.path}/`
                          + (options.flat ? '' : strings.dasherize(options.name) + '/')
                          + strings.dasherize(options.name)
                          + '.component';
    const relativePath = buildRelativePath(modulePath, componentPath);
    const classifiedName = strings.classify(`${options.name}Component`);
    const declarationChanges = addDeclarationToModule(source,
                                                      modulePath,
                                                      classifiedName,
                                                      relativePath);

    const declarationRecorder = host.beginUpdate(modulePath);
    for (const change of declarationChanges) {
      if (change instanceof InsertChange) {
        declarationRecorder.insertLeft(change.pos, change.toAdd);
      }
    }
    host.commitUpdate(declarationRecorder);

    if (options.export) {
      // Need to refresh the AST because we overwrote the file in the host.
      const text = host.read(modulePath);
      if (text === null) {
        throw new SchematicsException(`File ${modulePath} does not exist.`);
      }
      const sourceText = text.toString('utf-8');
      const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);

      const exportRecorder = host.beginUpdate(modulePath);
      const exportChanges = addExportToModule(source, modulePath,
                                              strings.classify(`${options.name}Component`),
                                              relativePath);

      for (const change of exportChanges) {
        if (change instanceof InsertChange) {
          exportRecorder.insertLeft(change.pos, change.toAdd);
        }
      }
      host.commitUpdate(exportRecorder);
    }


    return host;
  };
Example #3
0
  return (host: Tree) => {
    const clientProject = getProject(host, options.clientProject);
    const architect = getProjectTargets(clientProject);
    // const mainPath = universalArchitect.build.options.main;
    const modulePath = getServerModulePath(host, clientProject, architect);
    if (modulePath === null) {
      throw new SchematicsException('Universal/server module not found.');
    }

    let moduleSource = getSourceFile(host, modulePath);
    if (!isImported(moduleSource, 'Routes', '@angular/router')) {
      const recorder = host.beginUpdate(modulePath);
      const routesChange = insertImport(moduleSource,
                                        modulePath,
                                        'Routes',
                                        '@angular/router') as InsertChange;
      if (routesChange.toAdd) {
        recorder.insertLeft(routesChange.pos, routesChange.toAdd);
      }

      const imports = getSourceNodes(moduleSource)
        .filter(node => node.kind === ts.SyntaxKind.ImportDeclaration)
        .sort((a, b) => a.getStart() - b.getStart());
      const insertPosition = imports[imports.length - 1].getEnd();
      const routeText =
        `\n\nconst routes: Routes = [ { path: '${options.route}', component: AppShellComponent }];`;
      recorder.insertRight(insertPosition, routeText);
      host.commitUpdate(recorder);
    }

    moduleSource = getSourceFile(host, modulePath);
    if (!isImported(moduleSource, 'RouterModule', '@angular/router')) {
      const recorder = host.beginUpdate(modulePath);
      const routerModuleChange = insertImport(moduleSource,
                                              modulePath,
                                              'RouterModule',
                                              '@angular/router') as InsertChange;

      if (routerModuleChange.toAdd) {
        recorder.insertLeft(routerModuleChange.pos, routerModuleChange.toAdd);
      }

      const metadataChange = addSymbolToNgModuleMetadata(
          moduleSource, modulePath, 'imports', 'RouterModule.forRoot(routes)');
      if (metadataChange) {
        metadataChange.forEach((change: InsertChange) => {
          recorder.insertRight(change.pos, change.toAdd);
        });
      }
      host.commitUpdate(recorder);
    }


    return host;
  };
Example #4
0
  return (host: Tree) => {
    if (options.skipImport || !options.module) {
      return host;
    }

    const modulePath = options.module;
    const text = host.read(modulePath);
    if (text === null) {
      throw new SchematicsException(`File ${modulePath} does not exist.`);
    }
    const sourceText = text.toString('utf-8');
    const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);

    const pipePath = `/${options.path}/`
                     + (options.flat ? '' : strings.dasherize(options.name) + '/')
                     + strings.dasherize(options.name)
                     + '.pipe';
    const relativePath = buildRelativePath(modulePath, pipePath);
    const changes = addDeclarationToModule(source, modulePath,
                                           strings.classify(`${options.name}Pipe`),
                                           relativePath);
    const recorder = host.beginUpdate(modulePath);
    for (const change of changes) {
      if (change instanceof InsertChange) {
        recorder.insertLeft(change.pos, change.toAdd);
      }
    }
    host.commitUpdate(recorder);

    if (options.export) {
      const text = host.read(modulePath);
      if (text === null) {
        throw new SchematicsException(`File ${modulePath} does not exist.`);
      }
      const sourceText = text.toString('utf-8');
      const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);

      const exportRecorder = host.beginUpdate(modulePath);
      const exportChanges = addExportToModule(source, modulePath,
                                              strings.classify(`${options.name}Pipe`),
                                              relativePath);

      for (const change of exportChanges) {
        if (change instanceof InsertChange) {
          exportRecorder.insertLeft(change.pos, change.toAdd);
        }
      }
      host.commitUpdate(exportRecorder);
    }

    return host;
  };
Example #5
0
 return (host: Tree, context: SchematicContext) => {
   const packageJson = 'package.json';
   if (!host.exists(packageJson)) {
     throw new Error(`Could not find ${packageJson}`);
   }
   const content = host.read(packageJson).toString();
   const jsonAst = parseJsonAst(content);
   if (!isJsonAstObject(jsonAst)) {
     throw new Error(`Failed to parse JSON for ${packageJson}`);
   }
   const deps = findPropertyInAstObject(jsonAst, 'dependencies');
   if (!isJsonAstObject(deps)) {
     throw new Error(`Failed to find dependencies in ${packageJson}`);
   }
   const rxjs = findPropertyInAstObject(deps, 'rxjs');
   if (!rxjs) {
     throw new Error(`Failed to find rxjs in dependencies of ${packageJson}`);
   }
   const value = rxjs.value as string;  // value can be version or range
   const match = value.match(/(\d)+\.(\d)+.(\d)+$/);
   if (match) {
     const [_, major, minor] = match;
     if (major < '6' || (major === '6' && minor < '4')) {
       const recorder = host.beginUpdate(packageJson);
       replacePropertyInAstObject(recorder, deps, 'rxjs', '~6.4.0');
       host.commitUpdate(recorder);
     }
   } else {
     context.logger.info(
         'Could not determine version of rxjs. \n' +
         'Please make sure that version is at least 6.4.0.');
   }
   return host;
 };
Example #6
0
  return (host: Tree) => {
    const pkgJsonPath = '/package.json';
    const buffer = host.read(pkgJsonPath);
    if (!buffer) {
      throw new SchematicsException('Could not read package.json.');
    }

    const packageJsonAst = parseJsonAst(buffer.toString(), JsonParseMode.Strict);
    if (packageJsonAst.kind !== 'object') {
      throw new SchematicsException('Invalid package.json. Was expecting an object.');
    }

    const scriptsNode = findPropertyInAstObject(packageJsonAst, 'scripts');
    if (scriptsNode && scriptsNode.kind === 'object') {
      const recorder = host.beginUpdate(pkgJsonPath);
      const postInstall = findPropertyInAstObject(scriptsNode, 'postinstall');

      if (!postInstall) {
        // postinstall script not found, add it.
        insertPropertyInAstObjectInOrder(
          recorder,
          scriptsNode,
          'postinstall',
          'ivy-ngcc',
          4,
        );
      }

      host.commitUpdate(recorder);
    }
  };
  return (host: Tree) => {
    const tsConfigPath = '/tsconfig.json';
    const buffer = host.read(tsConfigPath);
    if (!buffer) {
      return host;
    }

    const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
    if (tsCfgAst.kind !== 'object') {
      return host;
    }

    const compilerOptions = findPropertyInAstObject(tsCfgAst, 'compilerOptions');
    if (!compilerOptions || compilerOptions.kind !== 'object') {
      return host;
    }

    const importHelpers = findPropertyInAstObject(compilerOptions, 'importHelpers');
    if (importHelpers && importHelpers.value === true) {
      return host;
    }

    const recorder = host.beginUpdate(tsConfigPath);
    if (importHelpers) {
      const { start, end } = importHelpers;
      recorder.remove(start.offset, end.offset - start.offset);
      recorder.insertLeft(start.offset, 'true');
    } else {
      insertPropertyInAstObjectInOrder(recorder, compilerOptions, 'importHelpers', true, 4);
    }
    host.commitUpdate(recorder);

    return host;
  };
Example #8
0
  return (host: Tree, context: SchematicContext) => {
    context.logger.debug('updating project configuration.');

    // Add worker glob exclusion to tsconfig.app.json.
    const workerGlob = 'src/**/*.worker.ts';
    const buffer = host.read(tsConfigPath);
    if (buffer) {
      const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
      if (tsCfgAst.kind != 'object') {
        throw new SchematicsException('Invalid tsconfig. Was expecting an object');
      }
      const filesAstNode = findPropertyInAstObject(tsCfgAst, 'exclude');
      if (filesAstNode && filesAstNode.kind != 'array') {
        throw new SchematicsException('Invalid tsconfig "exclude" property; expected an array.');
      }

      if (filesAstNode && !filesAstNode.value.includes(workerGlob)) {
        const recorder = host.beginUpdate(tsConfigPath);
        appendValueInAstArray(recorder, filesAstNode, workerGlob);
        host.commitUpdate(recorder);
      }
    }

    return mergeWith(
      apply(url('./files/worker-tsconfig'), [
        applyTemplates({
          ...options,
          relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(root),
        }),
        move(root),
      ]),
    );
  };
Example #9
0
export function appendHtmlElementToHead(host: Tree, htmlFilePath: string, elementHtml: string) {
  const htmlFileBuffer = host.read(htmlFilePath);

  if (!htmlFileBuffer) {
    throw new SchematicsException(`Could not read file for path: ${htmlFilePath}`);
  }

  const htmlContent = htmlFileBuffer.toString();

  if (htmlContent.includes(elementHtml)) {
    return;
  }

  const headTag = getHtmlHeadTagElement(htmlContent);

  if (!headTag) {
    throw `Could not find '<head>' element in HTML file: ${htmlFileBuffer}`;
  }

  // We always have access to the source code location here because the `getHeadTagElement`
  // function explicitly has the `sourceCodeLocationInfo` option enabled.
  const endTagOffset = headTag.sourceCodeLocation!.endTag.startOffset;
  const indentationOffset = getChildElementIndentation(headTag);
  const insertion = `${' '.repeat(indentationOffset)}${elementHtml}`;

  const recordedChange = host
    .beginUpdate(htmlFilePath)
    .insertRight(endTagOffset, `${insertion}\n`);

  host.commitUpdate(recordedChange);
}
Example #10
0
  visitor.missingInjectablePipes.forEach(data => {
    const {classDeclaration, importDeclarationMissingImport} = data;
    const sourceFile = classDeclaration.getSourceFile();
    const update = tree.beginUpdate(relative(basePath, sourceFile.fileName));

    // Note that we don't need to go through the AST to insert the decorator, because the change
    // is pretty basic. Also this has a better chance of preserving the user's formatting.
    update.insertLeft(classDeclaration.getStart(), `@${INJECTABLE_DECORATOR_NAME}()\n`);

    // Add @Injectable to the imports if it isn't imported already. Note that this doesn't deal with
    // the case where there aren't any imports for `@angular/core` at all. We don't need to handle
    // it because the Pipe decorator won't be recognized if it hasn't been imported from Angular.
    if (importDeclarationMissingImport) {
      const namedImports = getNamedImports(importDeclarationMissingImport);

      if (namedImports) {
        update.remove(namedImports.getStart(), namedImports.getWidth());
        update.insertRight(
            namedImports.getStart(),
            printer.printNode(
                ts.EmitHint.Unspecified, addImport(namedImports, INJECTABLE_DECORATOR_NAME),
                sourceFile));
      }
    }

    tree.commitUpdate(update);
  });
Example #11
0
  return (tree: Tree) => {
    const collectionJsonContent = tree.read('/.monorepo.json');
    if (!collectionJsonContent) {
      throw new Error('Could not find monorepo.json');
    }
    const collectionJsonAst = parseJsonAst(collectionJsonContent.toString('utf-8'));
    if (collectionJsonAst.kind !== 'object') {
      throw new Error('Invalid monorepo content.');
    }

    const packages = collectionJsonAst.properties.find(x => x.key.value == 'packages');
    if (!packages) {
      throw new Error('Cannot find packages key in monorepo.');
    }
    if (packages.value.kind != 'object') {
      throw new Error('Invalid packages key.');
    }

    const readmeUrl = `https://github.com/angular/devkit/blob/master/${path}/README.md`;

    const recorder = tree.beginUpdate('/.monorepo.json');
    appendPropertyInAstObject(
      recorder,
      packages.value,
      options.name,
      {
        name: options.displayName,
        links: [{ label: 'README', url: readmeUrl }],
        version: '0.0.1',
        hash: '',
      },
    );
    tree.commitUpdate(recorder);
  };
Example #12
0
  return (host: Tree) => {
    const workspace = getWorkspace(host);
    const project = getProjectFromWorkspace(workspace, options.project);
    const appModulePath = getAppModulePath(host, getProjectMainFile(project));
    const moduleSource = getSourceFile(host, appModulePath);

    const locale = getCompatibleLocal(options);
    const localePrefix = locale.split('_')[ 0 ];

    const recorder = host.beginUpdate(appModulePath);

    const changes = [
      insertImport(moduleSource, appModulePath, 'NZ_I18N',
        'ng-zorro-antd'),
      insertImport(moduleSource, appModulePath, locale,
        'ng-zorro-antd'),
      insertImport(moduleSource, appModulePath, 'registerLocaleData',
        '@angular/common'),
      insertImport(moduleSource, appModulePath, localePrefix,
        `@angular/common/locales/${localePrefix}`, true),
      registerLocaleData(moduleSource, appModulePath, localePrefix),
      ...insertI18nTokenProvide(moduleSource, appModulePath, locale)
    ];

    changes.forEach((change) => {
      if (change instanceof InsertChange) {
        recorder.insertLeft(change.pos, change.toAdd);
      }
    });

    host.commitUpdate(recorder);

    return host;
  };
Example #13
0
  return function(host: Tree): Tree {
    const workspace = getWorkspace(host);
    const project = getProjectFromWorkspace(workspace, options.project);

    // Because the build setup for the Angular CLI can be changed so dramatically, we can't know
    // where to generate anything if the project is not using the default config for build and test.
    assertDefaultProjectConfig(project);

    const stylesPath = getStylesPath(host, project);
    if (stylesPath.endsWith('.less')) {
      console.error(`Your project is not using less styles, current file: ${stylesPath}`);
    }
    const buffer = host.read(stylesPath);
    if (buffer) {
      const insertion = new InsertChange(
        stylesPath,
        0,
        createCustomTheme(project),
      );
      const recorder = host.beginUpdate(stylesPath);
      recorder.insertLeft(insertion.pos, insertion.toAdd);
      host.commitUpdate(recorder);
    } else {
      console.warn(`Skipped insert style; could not find file: ${stylesPath}`);
    }

    return host;
  };
Example #14
0
  return (host: Tree) => {
    const workspace = getWorkspace(host);
    const project = getProjectFromWorkspace(workspace, options.project);
    const styleFilePath = getProjectStyleFile(project);

    if (!styleFilePath) {
      console.warn(red(`Could not find the default style file for this project.`));
      console.warn(red(`Please consider manually setting up the Roboto font in your CSS.`));
      return;
    }

    const buffer = host.read(styleFilePath);

    if (!buffer) {
      console.warn(red(`Could not read the default style file within the project ` +
        `(${italic(styleFilePath)})`));
      console.warn(red(`Please consider manually setting up the Robot font.`));
      return;
    }

    const htmlContent = buffer.toString();
    const insertion = '\n' +
      `html, body { height: 100%; }\n` +
      `body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }\n`;

    if (htmlContent.includes(insertion)) {
      return;
    }

    const recorder = host.beginUpdate(styleFilePath);

    recorder.insertLeft(htmlContent.length, insertion);
    host.commitUpdate(recorder);
  };
Example #15
0
  return (host: Tree) => {
    const tsLintPath = '/tslint.json';
    const buffer = host.read(tsLintPath);
    if (!buffer) {
      return host;
    }
    const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);

    if (tsCfgAst.kind != 'object') {
      return host;
    }

    const rulesNode = findPropertyInAstObject(tsCfgAst, 'rules');
    if (!rulesNode || rulesNode.kind != 'object') {
      return host;
    }

    const recorder = host.beginUpdate(tsLintPath);

    rulesNode.properties.forEach(prop => {
      const mapping = ruleMapping[prop.key.value];
      if (mapping) {
        recorder.remove(prop.key.start.offset + 1, prop.key.value.length);
        recorder.insertLeft(prop.key.start.offset + 1, mapping);
      }
    });

    host.commitUpdate(recorder);

    return host;
  };
Example #16
0
  return (host: Tree) => {
    const clientTargets = getClientTargets(host, options);
    const mainPath = normalize('/' + clientTargets.build.options.main);
    let bootstrapCall: ts.Node | null = findBootstrapModuleCall(host, mainPath);
    if (bootstrapCall === null) {
      throw new SchematicsException('Bootstrap module not found.');
    }

    let bootstrapCallExpression: ts.Node | null = null;
    let currentCall = bootstrapCall;
    while (bootstrapCallExpression === null && currentCall.parent) {
      currentCall = currentCall.parent;
      if (currentCall.kind === ts.SyntaxKind.ExpressionStatement) {
        bootstrapCallExpression = currentCall;
      }
    }
    bootstrapCall = currentCall;

    const recorder = host.beginUpdate(mainPath);
    const beforeText = `document.addEventListener('DOMContentLoaded', () => {\n  `;
    const afterText = `\n});`;
    recorder.insertLeft(bootstrapCall.getStart(), beforeText);
    recorder.insertRight(bootstrapCall.getEnd(), afterText);
    host.commitUpdate(recorder);
  };
Example #17
0
  return (host: Tree) => {
    if (!options.module) {
      return host;
    }

    const modulePath = options.module;
    if (!host.exists(options.module)) {
      throw new Error('Specified module does not exist');
    }

    const text = host.read(modulePath);
    if (text === null) {
      throw new SchematicsException(`File ${modulePath} does not exist.`);
    }
    const sourceText = text.toString('utf-8');

    const source = ts.createSourceFile(
      modulePath,
      sourceText,
      ts.ScriptTarget.Latest,
      true
    );

    const commonImports = [
      insertImport(source, modulePath, 'StoreModule', '@ngrx/store'),
    ];

    const reducerPath =
      `/${options.path}/` +
      (options.flat ? '' : stringUtils.dasherize(options.name) + '/') +
      (options.group ? 'reducers/' : '') +
      stringUtils.dasherize(options.name) +
      '.reducer';
    const relativePath = buildRelativePath(modulePath, reducerPath);
    const reducerImport = insertImport(
      source,
      modulePath,
      `* as from${stringUtils.classify(options.name)}`,
      relativePath,
      true
    );
    const [storeNgModuleImport] = addImportToModule(
      source,
      modulePath,
      `StoreModule.forFeature('${stringUtils.camelize(
        options.name
      )}', from${stringUtils.classify(options.name)}.reducer)`,
      relativePath
    );
    const changes = [...commonImports, reducerImport, storeNgModuleImport];
    const recorder = host.beginUpdate(modulePath);
    for (const change of changes) {
      if (change instanceof InsertChange) {
        recorder.insertLeft(change.pos, change.toAdd);
      }
    }
    host.commitUpdate(recorder);

    return host;
  };
Example #18
0
/**
 * Insert a custom theme to project style file. If no valid style file could be found, a new
 * Scss file for the custom theme will be created.
 */
function insertCustomTheme(project: WorkspaceProject, projectName: string, host: Tree,
                           workspace: WorkspaceSchema) {

  const stylesPath = getProjectStyleFile(project, 'scss');
  const themeContent = createCustomTheme(projectName);

  if (!stylesPath) {
    if (!project.sourceRoot) {
      throw new SchematicsException(`Could not find source root for project: "${projectName}". ` +
        `Please make sure that the "sourceRoot" property is set in the workspace config.`);
    }

    // Normalize the path through the devkit utilities because we want to avoid having
    // unnecessary path segments and windows backslash delimiters.
    const customThemePath = normalize(join(project.sourceRoot, defaultCustomThemeFilename));

    if (host.exists(customThemePath)) {
      console.warn(yellow(`Cannot create a custom Angular Material theme because
          ${bold(customThemePath)} already exists. Skipping custom theme generation.`));
      return;
    }

    host.create(customThemePath, themeContent);
    addThemeStyleToTarget(project, 'build', host, customThemePath, workspace);
    return;
  }

  const insertion = new InsertChange(stylesPath, 0, themeContent);
  const recorder = host.beginUpdate(stylesPath);

  recorder.insertLeft(insertion.pos, insertion.toAdd);
  host.commitUpdate(recorder);
}
Example #19
0
  resolvedQueries.forEach((queries, sourceFile) => {
    const relativePath = relative(basePath, sourceFile.fileName);
    const update = tree.beginUpdate(relativePath);

    // Compute the query timing for all resolved queries and update the
    // query definitions to explicitly set the determined query timing.
    queries.forEach(q => {
      const queryExpr = q.decorator.node.expression;
      const {timing, message} = strategy.detectTiming(q);
      const result = getTransformedQueryCallExpr(q, timing, !!message);

      if (!result) {
        return;
      }

      const newText = printer.printNode(ts.EmitHint.Unspecified, result.node, sourceFile);

      // Replace the existing query decorator call expression with the updated
      // call expression node.
      update.remove(queryExpr.getStart(), queryExpr.getWidth());
      update.insertRight(queryExpr.getStart(), newText);

      if (result.failureMessage || message) {
        const {line, character} =
            ts.getLineAndCharacterOfPosition(sourceFile, q.decorator.node.getStart());
        failureMessages.push(
            `${relativePath}@${line + 1}:${character + 1}: ${result.failureMessage || message}`);
      }
    });

    tree.commitUpdate(update);
  });
Example #20
0
  importsMap.forEach((resolvedImport: ResolvedDocumentImport, sourceFile: ts.SourceFile) => {
    const {platformBrowserImport, commonImport, documentElement} = resolvedImport;
    if (!documentElement || !platformBrowserImport) {
      return;
    }
    const update = tree.beginUpdate(relative(basePath, sourceFile.fileName));

    const platformBrowserDeclaration = platformBrowserImport.parent.parent;
    const newPlatformBrowserText =
        removeFromImport(platformBrowserImport, sourceFile, DOCUMENT_TOKEN_NAME);
    const newCommonText = commonImport ?
        addToImport(commonImport, sourceFile, documentElement.name, documentElement.propertyName) :
        createImport(COMMON_IMPORT, sourceFile, documentElement.name, documentElement.propertyName);

    // Replace the existing query decorator call expression with the updated
    // call expression node.
    update.remove(platformBrowserDeclaration.getStart(), platformBrowserDeclaration.getWidth());
    update.insertRight(platformBrowserDeclaration.getStart(), newPlatformBrowserText);

    if (commonImport) {
      const commonDeclaration = commonImport.parent.parent;
      update.remove(commonDeclaration.getStart(), commonDeclaration.getWidth());
      update.insertRight(commonDeclaration.getStart(), newCommonText);
    } else {
      update.insertRight(platformBrowserDeclaration.getStart(), newCommonText);
    }

    tree.commitUpdate(update);
  });
Example #21
0
  return (tree: Tree) => {
    const collectionJsonContent = tree.read(collectionPath);
    if (!collectionJsonContent) {
      throw new Error('Invalid collection path: ' + collectionPath);
    }
    const collectionJsonAst = parseJsonAst(collectionJsonContent.toString('utf-8'));
    if (collectionJsonAst.kind !== 'object') {
      throw new Error('Invalid collection content.');
    }

    for (const property of collectionJsonAst.properties) {
      if (property.key.value == 'schematics') {
        if (property.value.kind !== 'object') {
          throw new Error('Invalid collection.json; schematics needs to be an object.');
        }

        const recorder = tree.beginUpdate(collectionPath);
        appendPropertyInAstObject(recorder, property.value, schematicName, description);
        tree.commitUpdate(recorder);

        return tree;
      }
    }

    throw new Error('Could not find the "schematics" property in collection.json.');
  };
Example #22
0
File: alain.ts Project: wexz/delon
export function addValueToVariable(
  host: Tree,
  path: string,
  variableName: string,
  text: string,
) {
  const source = getTsSource(host, path);
  const node = findNode(source, ts.SyntaxKind.Identifier, variableName);
  if (!node) {
    throw new SchematicsException(
      `Could not find any [${variableName}] variable.`,
    );
  }
  const arr = (node.parent as any).initializer as ts.ArrayLiteralExpression;

  const change = new InsertChange(
    path,
    arr.end - 1,
    `${arr.elements && arr.elements.length > 0 ? ',' : ''}\n  ${text}`,
  );

  const declarationRecorder = host.beginUpdate(path);
  declarationRecorder.insertLeft(change.pos, change.toAdd);
  host.commitUpdate(declarationRecorder);
}
/**
 * Remove the Reflect import from a polyfill file.
 * @param tree The tree to use.
 * @param path Path of the polyfill file found.
 * @private
 */
function _removeReflectFromPolyfills(tree: Tree, path: string) {
  const source = tree.read(path);
  if (!source) {
    return;
  }

  // Start the update of the file.
  const recorder = tree.beginUpdate(path);

  const sourceFile = ts.createSourceFile(path, source.toString(), ts.ScriptTarget.Latest);
  const imports = (
    sourceFile.statements
      .filter(s => s.kind === ts.SyntaxKind.ImportDeclaration) as ts.ImportDeclaration[]
  );

  for (const i of imports) {
    const module = i.moduleSpecifier.kind == ts.SyntaxKind.StringLiteral
      && (i.moduleSpecifier as ts.StringLiteral).text;

    switch (module) {
      case 'core-js/es7/reflect':
        recorder.remove(i.getStart(sourceFile), i.getWidth(sourceFile));
        break;
    }
  }

  tree.commitUpdate(recorder);
}
Example #24
0
  return (host: Tree) => {
    const packageJson = `${options.name}/package.json`;

    if (!host.exists(packageJson)) {
      throw new Error(`Could not find ${packageJson}`);
    }
    const packageJsonContent = host.read(packageJson);
    if (!packageJsonContent) {
      throw new Error('Failed to read package.json content');
    }
    const jsonAst = parseJsonAst(packageJsonContent.toString()) as JsonAstObject;
    const deps = findPropertyInAstObject(jsonAst, 'dependencies') as JsonAstObject;
    const devDeps = findPropertyInAstObject(jsonAst, 'devDependencies') as JsonAstObject;

    const angularCoreNode = findPropertyInAstObject(deps, '@angular/core');
    const angularCoreVersion = angularCoreNode !.value as string;

    const devDependencies: {[k: string]: string} = {
      '@angular/bazel': angularCoreVersion,
      // TODO(kyliau): Consider moving this to latest-versions.ts
      '@bazel/karma': '^0.22.0',
      '@bazel/typescript': '^0.22.0',
    };

    const recorder = host.beginUpdate(packageJson);
    for (const packageName of Object.keys(devDependencies)) {
      const version = devDependencies[packageName];
      const indent = 4;
      insertPropertyInAstObjectInOrder(recorder, devDeps, packageName, version, indent);
    }
    host.commitUpdate(recorder);
    return host;
  };
Example #25
0
    return (host: Tree) => {
        const modulePath = options.module as string;

        const text = host.read(modulePath);
        if (text === null) {
            throw new SchematicsException(`File ${modulePath} does not exist.`);
        }
        const sourceText = text.toString("utf-8");
        const source = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);

        const declarationChanges = addSymbolToNgModuleMetadata(
            source,
            modulePath,
            imports,
            moduleName,
            packageName
        );

        const declarationRecorder = host.beginUpdate(modulePath);
        for (const change of declarationChanges) {
            if (change instanceof InsertChange) {
                declarationRecorder.insertLeft(change.pos, change.toAdd);
            }
        }
        host.commitUpdate(declarationRecorder);

        return host;
    };
Example #26
0
export function addPackageJsonDependency(tree: Tree, dependency: NodeDependency): void {
  const packageJsonAst = _readPackageJson(tree);
  const depsNode = findPropertyInAstObject(packageJsonAst, dependency.type);
  const recorder = tree.beginUpdate(pkgJsonPath);
  if (!depsNode) {
    // Haven't found the dependencies key, add it to the root of the package.json.
    appendPropertyInAstObject(recorder, packageJsonAst, dependency.type, {
      [dependency.name]: dependency.version,
    }, 4);
  } else if (depsNode.kind === 'object') {
    // check if package already added
    const depNode = findPropertyInAstObject(depsNode, dependency.name);

    if (!depNode) {
      // Package not found, add it.
      insertPropertyInAstObjectInOrder(
        recorder,
        depsNode,
        dependency.name,
        dependency.version,
        4,
      );
    } else if (dependency.overwrite) {
      // Package found, update version if overwrite.
      const { end, start } = depNode;
      recorder.remove(start.offset, end.offset - start.offset);
      recorder.insertRight(start.offset, JSON.stringify(dependency.version));
    }
  }

  tree.commitUpdate(recorder);
}
Example #27
0
    apps.forEach((app: AppConfig, idx: number) => {
      const testTsConfig = app.testTsconfig || defaults.testTsConfig;
      const tsSpecConfigPath = join(normalize(app.root || ''), testTsConfig);
      const buffer = host.read(tsSpecConfigPath);

      if (!buffer) {
        return;
      }


      const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
      if (tsCfgAst.kind != 'object') {
        throw new SchematicsException('Invalid tsconfig. Was expecting an object');
      }

      const filesAstNode = findPropertyInAstObject(tsCfgAst, 'files');
      if (filesAstNode && filesAstNode.kind != 'array') {
        throw new SchematicsException('Invalid tsconfig "files" property; expected an array.');
      }

      const recorder = host.beginUpdate(tsSpecConfigPath);

      const polyfills = app.polyfills || defaults.polyfills;
      if (!filesAstNode) {
        // Do nothing if the files array does not exist. This means exclude or include are
        // set and we shouldn't mess with that.
      } else {
        if (filesAstNode.value.indexOf(polyfills) == -1) {
          appendValueInAstArray(recorder, filesAstNode, polyfills);
        }
      }

      host.commitUpdate(recorder);
    });
Example #28
0
 return (host: Tree, context: SchematicContext) => {
   if (!host.exists('angular-metadata.tsconfig.json')) {
     return;
   }
   const packageJson = 'package.json';
   if (!host.exists(packageJson)) {
     throw new Error(`Could not find ${packageJson}`);
   }
   const content = host.read(packageJson);
   if (!content) {
     throw new Error('Failed to read package.json content');
   }
   const jsonAst = parseJsonAst(content.toString());
   if (!isJsonAstObject(jsonAst)) {
     throw new Error(`Failed to parse JSON for ${packageJson}`);
   }
   const scripts = findPropertyInAstObject(jsonAst, 'scripts') as JsonAstObject;
   const recorder = host.beginUpdate(packageJson);
   if (scripts) {
     insertPropertyInAstObjectInOrder(
         recorder, scripts, 'postinstall', 'ngc -p ./angular-metadata.tsconfig.json', 4);
   } else {
     insertPropertyInAstObjectInOrder(
         recorder, jsonAst, 'scripts', {
           postinstall: 'ngc -p ./angular-metadata.tsconfig.json',
         },
         2);
   }
   host.commitUpdate(recorder);
   return host;
 };
Example #29
0
 return (host: Tree, context: SchematicContext) => {
   const tsconfigPath = 'tsconfig.json';
   if (!host.exists(tsconfigPath)) {
     return host;
   }
   const contentRaw = host.read(tsconfigPath) !.toString();
   if (!contentRaw) {
     return host;
   }
   const content = contentRaw.toString();
   const ast = parseJsonAst(content);
   if (!isJsonAstObject(ast)) {
     return host;
   }
   const compilerOptions = findPropertyInAstObject(ast, 'compilerOptions');
   if (!isJsonAstObject(compilerOptions)) {
     return host;
   }
   const recorder = host.beginUpdate(tsconfigPath);
   // target and module are controlled by downstream dependencies, such as
   // ts_devserver
   removeKeyValueInAstObject(recorder, content, compilerOptions, 'target');
   removeKeyValueInAstObject(recorder, content, compilerOptions, 'module');
   // typeRoots is always set to the @types subdirectory of the node_modules
   // attribute
   removeKeyValueInAstObject(recorder, content, compilerOptions, 'typeRoots');
   // rootDir and baseUrl are always the workspace root directory
   removeKeyValueInAstObject(recorder, content, compilerOptions, 'rootDir');
   removeKeyValueInAstObject(recorder, content, compilerOptions, 'baseUrl');
   host.commitUpdate(recorder);
   return host;
 };
Example #30
0
export function applyReplaceChange(tree: Tree, path: Path, ...changes: ReplaceChange[]): Tree {
  const recorder = tree.beginUpdate(path);
  changes.forEach(({ pos, oldText, newText }) => {
    recorder.remove(pos, oldText.length);
    recorder.insertLeft(pos, newText);
  });
  tree.commitUpdate(recorder);

  return tree;
}