1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

あるディレクトリ下にある.ts, .tsxファイルから、ramda.jsのどの関数が使用されているのかを調べるスクリプトをFSharpで書いてみた

Posted at

会社でramda.jsの研修用資料を作成することになりました。全部の関数を紹介するのは無理があるため、とりあえずあるモノレポで使われているramda.jsの関数をすべて調べることにしました。

open System.IO
(* dir pathを渡されると、再帰的にファイルのパスを返す関数 *)
let rec getFiles dir =
    let files = Directory.GetFiles(dir)
    let dirs = Directory.GetDirectories(dir)
    files |> Array.append (dirs |> Array.collect getFiles)

(* ファイルのextnameがts, tsxである場合のみtrue *)
let isTsOrTsx (filePath: string) =
    let ext = Path.GetExtension(filePath)
    ext = ".ts" || ext = ".tsx"

(* file pathにnode_modulesが含まれていたらexclude *)
let excludeNodeModules (filePath: string) =
    let nodeModulesIndex = filePath.IndexOf("node_modules")
    nodeModulesIndex = -1

(* ().ts or .tsx) && not node_modules *)
let validFiles (dirPath: string) =
    getFiles dirPath |> Seq.filter isTsOrTsx |> Seq.filter excludeNodeModules

(* ファイルの中を1行ずつ確認し、"ramda"という単語があれば、その行を返す *)
let isRamdaLine (filePath: string) =
    let lines = File.ReadAllLines(filePath)

    lines
    (* ramdaがあれば返すけれど、複数行あってimport文が終了のときはNG *)
    |> Seq.filter (fun line -> line.Contains("\"ramda\"") && not (line = "} from \"ramda\";"))

(*
  import { drop, includes, take } from "ramda";
  こうあったときに、drop, includes, takeを取り出す
*)

let takeFunctionName (line: string) =
    (* lineがlength0であれば空 *)
    if line.Length = 0 then
        [||]
    else
        (* 文字をseqとして考えて、「{」が来るまでを削除。 *)
        let dropUntilBrace = line |> Seq.skipWhile (fun c -> c <> '{')
        (* 「{」を削除 *)
        let dropBrace = dropUntilBrace |> Seq.skip 1
        (* 「}」が来るまでを取得 *)
        let takeUntilBrace = dropBrace |> Seq.takeWhile (fun c -> c <> '}')
        let t = takeUntilBrace |> Seq.toArray |> System.String.Concat
        (* カンマがあればsplitしてtrimする *)
        let splitByComma = t.Split(',') |> Array.map (fun s -> s.Trim())
        (* join *)
        splitByComma

(* entry point *)
[<EntryPoint>]
let main argv =
    let dir = Seq.tryHead argv

    match dir with
    | Some dir ->
        let absolutePath = Path.GetFullPath(dir)
        let seqs = validFiles absolutePath |> Seq.collect isRamdaLine

        seqs
        |> Seq.map takeFunctionName
        |> Seq.concat
        |> Seq.distinct
        |> Seq.sort
        |> Seq.iter (fun s -> printfn "%A" s)

    | None ->
        printfn "no dir"
        exit 1

    exit 0

ちょっと力技で解決したところもありますが……。
普段はこんなにコメント書きませんが、あんまり使わない言語はcopilotに頑張ってほしくてコメント多めです。あとで見たときにコメントがないと、メイン言語以外だと本当にリーディング辛いし。

ということで、わが社のモノレポでは
"append"
"clone"
"collectBy"
"concat"
"difference"
"drop"
"dropLast"
"equals"
"filter"
"flatten"
"fromPairs"
"head"
"includes"
"insert"
"intersection"
"isEmpty"
"isNil"
"keys"
"last"
"map"
"mergeAll"
"move"
"omit"
"partition"
"pick"
"pickAll"
"pipe"
"pluck"
"prop"
"range"
"reject"
"remove"
"repeat"
"reverse"
"sortBy"
"splitEvery"
"sum"
"tail"
"take"
"takeLast"
"toPairs"
"union"
"uniq"
"values"
"without"
"xprod"
という関数が使用されていました。
どうせならuniqというかdistinctする前にカウントしておいて頻度順に並べ替えできるようにすれば良かったな。というか、そのように作り直しましょう。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?