Skip to content

Commit

Permalink
[feat]: added --input-dir argument
Browse files Browse the repository at this point in the history
  • Loading branch information
believelody committed Jun 19, 2024
1 parent 550d6fb commit bfa8f4e
Show file tree
Hide file tree
Showing 23 changed files with 620 additions and 51 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# balukajs

## 1.4.0

### Minor Changes

- added -I / --input-dir to manage directory conversion.

## 1.3.0

### Minor Changes
Expand Down
Binary file modified bun.lockb
Binary file not shown.
2 changes: 1 addition & 1 deletion jsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"module": "CommonJS",
"module": "ESNext",
"target": "ES6",

/* Bundler mode */
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "balukajs",
"version": "1.3.0",
"version": "1.4.0",
"main": "src/index.js",
"author": {
"name": "billybillydev",
Expand Down Expand Up @@ -57,6 +57,7 @@
"change-case": "^5.4.4",
"chokidar": "^3.6.0",
"commander": "^12.1.0",
"dir-to-json": "^1.0.0",
"jest": "^29.7.0",
"tsup": "^8.0.2"
}
Expand Down
33 changes: 22 additions & 11 deletions src/commands/convert.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,45 @@
import { jsonToJSDocTypes } from "$lib/json-to-jsdoc";
import { buildJsonSchema } from "$lib/json-to-schema";
import { jsonToTSInterface } from "$lib/json-to-ts-interface";
import { organizeToJSON } from "$lib/utils";
import chalk from "chalk";
import fs from "fs";
import { lstat } from "node:fs/promises";
import path from "path";

/**
* Function responsible for converting input into formatted output
* @param {Object} data
* @param {string} data.input
* @param {string=} data.input
* @param {string=} data.inputDir
* @param {string=} data.output
* @param {string=} data.name
* @param {FormatType=} data.format
* @returns {void}
* @example
* convert({ input: "example.json", format: "jsdoc", name: "IExample" })
*/
export function convert({ input, output, name, format }) {
if (!input) {
throw new Error("Missing -i or --input option");
export async function convert({ input, inputDir, output, name, format }) {
const source = inputDir ?? input;
if (!source) {
throw new Error("Missing -i / --input and -I / --input-dir arguments");
}
if (!fs.existsSync(input)) {
throw new Error("No file");
if (!fs.existsSync(source)) {
throw new Error("No file or directory");
}

if (path.extname(input) !== ".json") {
throw new Error("File is not json");
let data;
const stats = await lstat(source);
if (stats.isDirectory()) {
data = JSON.stringify(await organizeToJSON(source));
} else {
if (path.extname(input) !== ".json") {
throw new Error("File is not json");
}
data = fs.readFileSync(input, "utf-8");
}
if (!data) {
throw new Error("Data is null or undefined");
}

const data = fs.readFileSync(input, "utf-8");
let result = "";
const defaultName = "MyType";

Expand Down
40 changes: 31 additions & 9 deletions src/commands/watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,37 @@ import chokidar from "chokidar";

/**
* @param {Object} data
* @param {string} data.input
* @param {string=} data.output
* @param {string=} data.name
* @param {FormatType=} data.format
* @param {string} data.input
* @param {string} data.inputDir
* @param {string=} data.output
* @param {string=} data.name
* @param {FormatType=} data.format
* @returns {void}
*/
export function watch({ input, output, name, format }) {
chokidar.watch(input).on("change", () => {
console.log("File changed, re-running conversion...");
convert({ input, output, name, format });
});
export function watch({ input, inputDir, output, name, format }) {
if (inputDir) {
chokidar
.watch(inputDir)
.on("ready", () => {
console.log("Scan completed, running conversion...");
convert({ inputDir, output, name, format });
})
.on("change", (path) => {
console.log("%s updated, re-running conversion...", path);
convert({ inputDir, output, name, format });
})
.on("unlink", (path) => {
console.log("File at path: % removed, re-running conversion...", path);
convert({ inputDir, output, name, format });
})
.on("unlinkDir", (path) => {
console.log("Directory at path: %s removed, re-running conversion...", path);
convert({ inputDir, output, name, format });
});
} else if (input) {
chokidar.watch(input).on("change", (path) => {
console.log("File at path: %s changed, re-running conversion...", path);
convert({ input, output, name, format });
});
}
}
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ async function main() {
"display the version number"
)
.option("-i, --input <path>", "input JSON file")
.option("-I, --input-dir <path>", "input directory containing directories and json files")
.option("-o, --output <path>", "output file")
.option("--name <typeName>", "name of the type")
.option("--format <format>", "output format (jsdoc, ts or schema)", "jsdoc")
Expand All @@ -30,7 +31,6 @@ async function main() {
if (process.argv.length <= 2) {
program.help();
}

const { watch, ...restProps } = program.opts();

if (watch) {
Expand Down
83 changes: 83 additions & 0 deletions src/lib/utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
import dirToJson from "dir-to-json";
import path from "path";
import fs from "fs";
import { camelCase } from "change-case";

/**
* @typedef {object} StructureInfo
* @property {string} parent
* @property {string} path
* @property {string} name
* @property {"directory" | "file"} type
* @property {StructureInfo[]} [children]
*/

/**
* @typedef {object} SimpleStructureInfo
* @type {Record<string, string | object>}
*/

/**
* @param {object[]} objectArray
* @returns {string[]}
Expand All @@ -17,3 +36,67 @@ export function detectOptionalProperties(objectArray) {

return optionalProperties;
}

/**
* Takes a directory path and transform its structure to json tree object
* @param {string} directoryPath
* @returns {Object}
*/
export async function organizeToJSON(directoryPath) {
/** @type {StructureInfo} */
const directoryObject = await dirToJson(directoryPath);
const simpleObject = await simplifyObject(directoryObject, directoryPath);
return sortObjectByKeys(simpleObject);
}

/**
* Takes a StructureInfo object and returns a SimpleStructureInfo
* @param {StructureInfo} obj
* @param {string} rootPath
* @returns {SimpleStructureInfo}
*/
async function simplifyObject(obj, rootPath) {
const simpleObject = {};
if (obj.type === "directory") {
for await (const child of obj.children) {
const childObject = await simplifyObject(child, rootPath);
if (childObject) {
if (child.type === "file") {
Object.entries(childObject).forEach(([k, v]) => {
simpleObject[k] = v;
});
} else {
const name =
child.name.includes(".") || child.name.includes("-")
? camelCase(child.name)
: child.name;
simpleObject[name] = childObject;
}
}
}
} else if (obj.type === "file") {
const filePath = path.join(rootPath, obj.path);
const isFileExists = await fs.existsSync(filePath);
const fileExtension = path.extname(filePath);
if (isFileExists) {
if (fileExtension !== ".json") {
return null;
}
const fileName = path.basename(filePath, fileExtension);
const file = await fs.readFileSync(filePath, "utf-8");
const name =
fileName.includes(".") || fileName.includes("-")
? camelCase(fileName)
: fileName;
simpleObject[name] = file;
}
}
return simpleObject;
}

export function sortObjectByKeys(obj) {
// Convert object to an array of key-value pairs, sort it, and convert back to an object
return Object.fromEntries(
Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB))
);
}
2 changes: 1 addition & 1 deletion src/types/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
/**
* @typedef {"json" | "ts" | "schema"} FormatType
* @typedef {"jsdoc" | "ts" | "schema"} FormatType
*/
Loading

0 comments on commit bfa8f4e

Please sign in to comment.