首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型记录:递归文件-系统查找

类型记录:递归文件-系统查找
EN

Code Review用户
提问于 2017-08-23 10:32:42
回答 1查看 536关注 0票数 2

之前,我问了一个问题,以找到递归运行函数以检索NodeJs 这里中文件的所有导入/导出语句的最佳实践。

经过一些讨论后,我还不满意,所以我将把我在前面的讨论中学到的代码重新写出来,希望能找到一种更好的方法,或者简单地对我的代码进行审查。

我调用preprocessTSFiles函数,它使用入口点运行getFiles,并返回它的所有导入/导出语句加上自身,这将导致从VinylFile类递归调用getImporters

preprocess-files.ts

代码语言:javascript
复制
import * as path from 'path';
import * as vinyl from 'vinyl';
import { VinylFile } from './file';
import {
  ensureMakeDir,
  isArray,
  isDirectory,
  isEmpty,
  isFile,
  isNil,
  readFile,
  writeFile,
} from './utils';

import { InlineStyles } from './plugins/inline-styles';
import { InlineTemplate } from './plugins/inline-template';

export interface HandlerPlugin {
  (file: VinylFile): Promise<string>;
}

export async function preprocessTSFiles(entryFilePath: string, destDir: string, baseDir?: string): Promise<void> {
  const fileList: string[] = [];
  const plugins = [InlineTemplate, InlineStyles];

  if (isNil(baseDir)) {
    baseDir = path.dirname(entryFilePath);
  }

  const allFiles = await getFiles(entryFilePath, []);

  for (const file of allFiles) {
    for (const plugin of plugins) {
      const newContent = await plugin(file);

      if (newContent != file.content) {
        file.setContent(newContent);
      }
    }

    const currentPath = file.filePath;
    const destPath = currentPath.replace(baseDir + path.sep, '');
    const absDestPath = path.resolve(destDir, destPath);

    file.copyTo(absDestPath);
  }
}

async function getFiles(entryFilePath: string, excludeList: string[]): Promise<VinylFile[]> {
  const entryFile = new VinylFile(entryFilePath);
  const excludeFromList: string[] = [entryFilePath];
  return [entryFile, ...await entryFile.getImporters(excludeFromList)];
}

file.ts

代码语言:javascript
复制
import * as path from 'path';
import {
  ensureMakeDir,
  isDirectory,
  isFile,
  isNil,
  readFile,
  writeFile,
} from './utils';

export class VinylFile {
  private _content: string;
  private importStatementRE = /(?:import|export)\s*(?:(?:\{[^}]*\}|\*|\w+)(?:\s*as\s+\w+)?(?:\s+from)?\s*)?([`'"])((?:\\[\s\S]|(?!\1)[^\\])*?)\1/ig;

  public dirPath: string;

  constructor(public filePath: string) {
    this.dirPath = path.dirname(filePath);
  }

  get content(): string {
    if (isNil(this._content)) {
      this._content = readFile(this.filePath);
    }

    return this._content;
  }

  public setContent(content: string): void {
    this._content = content;
  }

  public copyTo(destFilePath: string): void {
    const dirPath = path.dirname(destFilePath);
    ensureMakeDir(dirPath);
    writeFile(destFilePath, this.content);
  }

  public hasImporters(): boolean {
    this.importStatementRE.lastIndex = 0;
    return this.importStatementRE.test(this.content);
  }

  public async getImporters(excludeFrom?: string[]): Promise<VinylFile[]> {
    const importees: VinylFile[] = [];
    const importStatementMatchIndex = 2;
    let importersMatch: RegExpMatchArray | null;

    if (isNil(excludeFrom)) {
      excludeFrom = [];
    }

    // Reset current index to 0
    // RegEx.test moves this into 1
    this.importStatementRE.lastIndex = 0;
    while ((importersMatch = this.importStatementRE.exec(this.content)) && !isNil(importersMatch)) {
      const importee = importersMatch[importStatementMatchIndex];
      const resolvedPath = path.resolve(this.dirPath, importee);

      if (isDirectory(resolvedPath)) {
        const resolvedIndexFilePath = path.resolve(resolvedPath, 'index.ts');

        if (isFile(resolvedIndexFilePath) && excludeFrom.indexOf(resolvedIndexFilePath) < 0) {
          const resolvedIndexFile = new VinylFile(resolvedIndexFilePath);
          excludeFrom.push(resolvedIndexFilePath);
          importees.push(resolvedIndexFile);

          if (resolvedIndexFile.hasImporters()) {
            importees.push(...await resolvedIndexFile.getImporters(excludeFrom));
          }
        }
      } else {
        let resolvedFilePath = resolvedPath;
        if (path.extname(resolvedFilePath) !== '.ts') {
          resolvedFilePath += '.ts';
        }

        if (isFile(resolvedFilePath) && excludeFrom.indexOf(resolvedFilePath) < 0) {
          const resolvedFile = new VinylFile(resolvedFilePath);
          excludeFrom.push(resolvedFilePath);
          importees.push(resolvedFile);

          if (resolvedFile.hasImporters()) {
            importees.push(...await resolvedFile.getImporters(excludeFrom));
          }
        }
      }
    }
    return importees;
  }
}
EN

回答 1

Code Review用户

发布于 2017-08-23 19:32:01

我看到在重构之后,您的代码更易读。

你选择了更好的名字来澄清意图。这是一个很好的部分。

我认为思考的重点是时间的部分。

以功能的方式,您可以改进代码,将匹配的部分放入方法中:

代码语言:javascript
复制
getImportStatements() {
  const importStatementMatchIndex = 2;
  const importStatements = [];
  let importersMatch = this.importStatementRE.exec(this.content);
  while(!isNil(impotersMatch)) {
    importStatements.push(impotersMatch[importStatementMatchIndex]);
    importersMatch = this.importStatementRE.exec(this.content);
  }
  return importStatements;
}

这将只返回一个具有匹配字符串的列表。进行此更改的原因是试图以一种代码易于阅读和更改的方式来划分响应。

此方法隔离了如何获取源文件上的导入列表的逻辑。

然后可以重写main方法,删除while循环并添加以下内容:

代码语言:javascript
复制
this.getImportStatements()
  .map((importee) => (path.resolve(this.dirPath, importee)))
  .map((resolvedPath) => {
    if (isDirectory(resolvedPath)) {
      return path.resolve(resolvedPath, 'index.ts');
    }
    return (path.extname(resolvedPath) !== '.ts') ? resolvedPath += '.ts' : resolvedPath;
  })
  .filter((resolvedFilePath) => (!isFile(resolvedFilePath) || excludeFrom.indexOf(resolvedFilePath) >= 0))
  .forEach((resolvedFilePath) => {
    const resolvedFile = new VinylFile(resolvedFilePath);
    excludeFrom.push(resolvedFilePath);
    importees.push(resolvedFile);

    if (resolvedFile.hasImporters()) {
      importees.push(...await resolvedFile.getImporters(excludeFrom));
    }
  });

其原则是附加从getImportStatements()返回的数组,以保证至少返回一个空数组。

然后使用javascript数组方法将字符串映射到完整路径,然后过滤,然后收集。

可以随意更改方法中的箭头函数,以增加代码的可读性。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/173747

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档