본문 바로가기
개발/Node JS

Node JS - Chonky 파일 맵 만들기 (Make Chonky File Map)

by 피로물든딸기 2024. 3. 16.
반응형

리액트 전체 링크

Node JS 전체 링크

 

참고

- 파일 브라우저 만들기
- chonky 기본 설정 확인하기
- 액션 추가하고 다크 모드 구현하기
커스텀 액션 추가하기
- Chonky 파일 맵 만들기
- 리포지토리의 폴더 정보 저장하기
- 깃허브 리포지토리를 파일 브라우저로 불러오기
useNavigate로 Toast UI Editor 이동하기

 

Chonky 브라우저에서 사용하는 예시 demo.json은 다음과 같다.

 

1) 최상위 폴더의 IDrootFolderId가 필요하다.

2) fileMap에서 전체 폴더/파일에 대한 정보가 있다.

3) 폴더의 경우, isDirchildrenIds, childrenCount 정보가 있다.

4) 파일의 경우, sizeisHidden 정보가 있다.

5) 폴더와 파일 모두 parentId를 알고 있어야 한다.

{
    "rootFolderId": "qwerty123456",
    "fileMap": {
        "qwerty123456": {
            "id": "qwerty123456",
            "name": "Chonkyz Demo",
            "isDir": true,
            "childrenIds": [
                "e598a85f843c",
                "b53aa057fad1",
                "b6667221f24b",
                "002705459ca4",
                "a9fd7c8a04db",
                "549c1f93247a",
                "zFe",
                "zJr",
                "zHy",
                "vCt"
            ],
            "childrenCount": 6
        },
        
        ...
        
        "9514a3d74d57": {
            "id": "9514a3d74d57",
            "name": ".eslintrc.js",
            "isHidden": true,
            "size": 2293,
            "modDate": "2020-10-20T03:11:50.570Z",
            "parentId": "e598a85f843c"
        },
        
        ...

 

요약하면 폴더는 아래와 같은 정보를 가져야 한다.

let dir = {
  id: "",
  name: "",
  isDir: true,
  modDate: "",
  childrenIds: [],
  childrenCount: 0,
  parentId: "",
};

 

파일은 isHidden과 같은 정보는 제외하고 아래의 정보를 가지도록 Node JS로 구현해 보자.

let file = {
  id: "",
  name: "",
  size: "",
  modDate: "",
  parentId: "",
};

구현

 

아래의 폴더, 파일루트 폴더(= myfiles)에 있다고 가정하자.

 

파일이 필요하면 아래 zip 파일을 참고하면 된다.

myfiles.zip
0.00MB

 

먼저 각 폴더, 파일마다 recursive하게 유일한 ID를 만들자.

makePathIdMap에서 directory인 경우, 해당 폴더에 들어가서 ID를 만들면 된다.

ID가 유일하기만 하면 되기 때문에, 순서는 상관없고 pathIdMap[전체 경로 이름] = ID 로 저장하였다.

전체 경로path.join을 이용해서 얻을 수 있다.

// make_dir_map.js

let pathIdMap = {};
let id_counter = 0;

const makePathIdMap = (dir) => {
  pathIdMap[dir] = `id_${id_counter++}`;
  let items = fs.readdirSync(dir);
  for (let item of items) {
    let itemPath = path.join(dir, item);
    let stats = fs.statSync(itemPath);

    if (stats.isDirectory()) {
      makePathIdMap(itemPath);
    } else if (stats.isFile()) {
      pathIdMap[itemPath] = `id_${id_counter++}`;
    }
  }
};

 

childrenCountchildrenIds는 다음과 같이 구할 수 있다.

const getChildrenCount = (dir) => {
  let items = fs.readdirSync(dir);
  return items.length;
};

const getChildrenIds = (dir) => {
  let ret = [];
  let items = fs.readdirSync(dir);
  for (let item of items) {
    let itemPath = path.join(dir, item);
    ret.push(pathIdMap[itemPath]);
  }

  return ret;
};

 

이제 makeChonkyMap을 이용해서 위와 마찬가지로 recursive하게 chonky map을 만들면 된다.

id, childrenIds, childrenCount, parentId는 미리 만들어두었고, 그 외 내용은 statSync를 이용해서 얻을 수 있다.

폴더인 경우에만 isDir : true로 설정하고, 파일의 경우에는 size를 구하도록 하였다.

let makeChonkyMap = (dir) => {
  let items = fs.readdirSync(dir);

  for (let item of items) {
    let itemPath = path.join(dir, item);
    let stats = fs.statSync(itemPath);

    // 현재 폴더에 있는 폴더와 파일을 먼저 처리
    if (stats.isDirectory()) {
      let obj = {
        id: pathIdMap[itemPath],
        name: item,
        isDir: true,
        modDate: fs.statSync(itemPath).mtime,
        childrenIds: getChildrenIds(itemPath),
        childrenCount: getChildrenCount(itemPath),
        parentId: pathIdMap[dir],
      };

      fileMap[pathIdMap[itemPath]] = obj;
      makeChonkyMap(itemPath);
    } else if (stats.isFile()) {
      let obj = {
        id: pathIdMap[itemPath],
        name: item,
        size: fs.statSync(itemPath).size,
        modDate: fs.statSync(itemPath).mtime,
        parentId: pathIdMap[dir],
      };

      fileMap[pathIdMap[itemPath]] = obj;
    }
  }
};

 

이제 설정한 루트 폴더(dirPath)에 대해 map을 만들면 된다.

makePathIdMap으로 ID를 먼저 만들고, fileMap root 폴더를 초기화하였다.

마지막으로 dir_map.json을 만들 때 rootFolderIdfileMapwrite하면 된다.

makePathIdMap(dirPath);

let rootFolderId = `id_0`;
let initCount = getChildrenCount(dirPath);
let initChildrenIds = getChildrenIds(dirPath);

let fileMap = {
  id_0: {
    id: rootFolderId,
    name: "myfiles", // root folder name
    isDir: true,
    childrenIds: initChildrenIds,
    childrenCount: initCount,
  },
};

makeChonkyMap(dirPath);

let json = JSON.stringify({ rootFolderId, fileMap }, null, 4);
fs.writeFileSync("dir_map.json", json, "utf-8");

 

예시의 루트 폴더에 대한 chonky file map은 다음과 같다.

{
    "rootFolderId": "id_0",
    "fileMap": {
        "id_0": {
            "id": "id_0",
            "name": "myfiles",
            "isDir": true,
            "childrenIds": [
                "id_1",
                "id_5",
                "id_11",
                "id_12",
                "id_13"
            ],
            "childrenCount": 5
        },
        "id_1": {
            "id": "id_1",
            "name": "handsontable",
            "isDir": true,
            "modDate": "2024-03-16T08:55:22.649Z",
            "childrenIds": [
                "id_2",
                "id_3",
                "id_4"
            ],
            "childrenCount": 3,
            "parentId": "id_0"
        },
        "id_2": {
            "id": "id_2",
            "name": "data1.json",
            "size": 0,
            "modDate": "2024-03-16T08:55:06.480Z",
            "parentId": "id_1"
        },
        "id_3": {
            "id": "id_3",
            "name": "data2.json",
            "size": 0,
            "modDate": "2024-03-16T08:55:06.480Z",
            "parentId": "id_1"
        },
        "id_4": {
            "id": "id_4",
            "name": "data3.json",
            "size": 0,
            "modDate": "2024-03-16T08:55:06.480Z",
            "parentId": "id_1"
        },
        "id_5": {
            "id": "id_5",
            "name": "markdown",
            "isDir": true,
            "modDate": "2024-03-16T08:54:25.907Z",
            "childrenIds": [
                "id_6",
                "id_10"
            ],
            "childrenCount": 2,
            "parentId": "id_0"
        },
        "id_6": {
            "id": "id_6",
            "name": "information",
            "isDir": true,
            "modDate": "2024-03-16T08:54:40.968Z",
            "childrenIds": [
                "id_7",
                "id_8",
                "id_9"
            ],
            "childrenCount": 3,
            "parentId": "id_5"
        },
        "id_7": {
            "id": "id_7",
            "name": "info1.md",
            "size": 14,
            "modDate": "2023-06-02T06:45:33.755Z",
            "parentId": "id_6"
        },
        "id_8": {
            "id": "id_8",
            "name": "info2.md",
            "size": 14,
            "modDate": "2023-06-02T06:45:33.755Z",
            "parentId": "id_6"
        },
        "id_9": {
            "id": "id_9",
            "name": "info3.md",
            "size": 14,
            "modDate": "2023-06-02T06:45:33.755Z",
            "parentId": "id_6"
        },
        "id_10": {
            "id": "id_10",
            "name": "Manual.md",
            "size": 14,
            "modDate": "2023-06-02T06:45:33.755Z",
            "parentId": "id_5"
        },
        "id_11": {
            "id": "id_11",
            "name": "package-lock.json",
            "size": 3,
            "modDate": "2023-06-02T06:44:17.496Z",
            "parentId": "id_0"
        },
        "id_12": {
            "id": "id_12",
            "name": "package.json",
            "size": 3,
            "modDate": "2023-06-02T06:44:07.929Z",
            "parentId": "id_0"
        },
        "id_13": {
            "id": "id_13",
            "name": "README.md",
            "size": 3,
            "modDate": "2023-06-02T06:44:17.496Z",
            "parentId": "id_0"
        }
    }
}

 

dir_map.jsonChonky Browserdemo.json에 붙여넣자.

정상적으로 폴더가 반영되는 것을 알 수 있다.

 

전체 코드는 다음과 같다.

const fs = require("fs");
const path = require("path");

const dirPath = "D:\\github\\node-server\\macro\\myfiles"; // window path

let pathIdMap = {};
let id_counter = 0;

const makePathIdMap = (dir) => {
  pathIdMap[dir] = `id_${id_counter++}`;
  let items = fs.readdirSync(dir);
  for (let item of items) {
    let itemPath = path.join(dir, item);
    let stats = fs.statSync(itemPath);

    if (stats.isDirectory()) {
      makePathIdMap(itemPath);
    } else if (stats.isFile()) {
      pathIdMap[itemPath] = `id_${id_counter++}`;
    }
  }
};

const getChildrenCount = (dir) => {
  let items = fs.readdirSync(dir);
  return items.length;
};

const getChildrenIds = (dir) => {
  let ret = [];
  let items = fs.readdirSync(dir);
  for (let item of items) {
    let itemPath = path.join(dir, item);
    ret.push(pathIdMap[itemPath]);
  }

  return ret;
};

let makeChonkyMap = (dir) => {
  let items = fs.readdirSync(dir);

  for (let item of items) {
    let itemPath = path.join(dir, item);
    let stats = fs.statSync(itemPath);

    // 현재 폴더에 있는 폴더와 파일을 먼저 처리
    if (stats.isDirectory()) {
      let obj = {
        id: pathIdMap[itemPath],
        name: item,
        isDir: true,
        modDate: fs.statSync(itemPath).mtime,
        childrenIds: getChildrenIds(itemPath),
        childrenCount: getChildrenCount(itemPath),
        parentId: pathIdMap[dir],
      };

      fileMap[pathIdMap[itemPath]] = obj;
      makeChonkyMap(itemPath);
    } else if (stats.isFile()) {
      let obj = {
        id: pathIdMap[itemPath],
        name: item,
        size: fs.statSync(itemPath).size,
        modDate: fs.statSync(itemPath).mtime,
        parentId: pathIdMap[dir],
      };

      fileMap[pathIdMap[itemPath]] = obj;
    }
  }
};

makePathIdMap(dirPath);

let rootFolderId = `id_0`;
let initCount = getChildrenCount(dirPath);
let initChildrenIds = getChildrenIds(dirPath);

let fileMap = {
  id_0: {
    id: rootFolderId,
    name: "myfiles",
    isDir: true,
    childrenIds: initChildrenIds,
    childrenCount: initCount,
  },
};

makeChonkyMap(dirPath);

let json = JSON.stringify({ rootFolderId, fileMap }, null, 4);
fs.writeFileSync("dir_map.json", json, "utf-8");
반응형

댓글