├── .prettierrc.json ├── dist ├── cjs │ ├── package.json │ ├── index.d.ts │ └── index.js └── esm │ ├── index.d.ts │ └── index.js ├── .eslintignore ├── .prettierignore ├── jest.config.ts ├── .gitignore ├── .eslintrc.json ├── .github ├── FUNDING.yml └── workflows │ └── test.yml ├── .npmignore ├── tsconfig.json ├── tsconfig.cjs.json ├── LICENSE ├── CHANGELOG.md ├── SECURITY.md ├── test └── index.test.js ├── package.json ├── CODE_OF_CONDUCT.md ├── README.md └── src └── index.ts /.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /dist/cjs/package.json: -------------------------------------------------------------------------------- 1 | {"type": "commonjs"} 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | test/ 3 | node_modules 4 | coverage -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.md 2 | build 3 | dist 4 | node_modules 5 | coverage 6 | 7 | # Ignore lock files (optional, up to you) 8 | package-lock.json 9 | yarn.lock 10 | 11 | # Ignore misc 12 | *.log 13 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "jest"; 2 | 3 | const config: Config = { 4 | clearMocks: true, 5 | collectCoverage: true, 6 | coverageDirectory: "coverage", 7 | }; 8 | 9 | export default config; 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | coverage 3 | 4 | # Ignore lock files (optional, up to you) 5 | package-lock.json 6 | yarn.lock 7 | 8 | # Ignore misc 9 | *.log 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true, 5 | "node": true 6 | }, 7 | "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"], 8 | "parser": "@typescript-eslint/parser", 9 | "parserOptions": { 10 | "ecmaVersion": "latest", 11 | "sourceType": "module" 12 | }, 13 | "plugins": ["@typescript-eslint"], 14 | "rules": {} 15 | } 16 | -------------------------------------------------------------------------------- /dist/cjs/index.d.ts: -------------------------------------------------------------------------------- 1 | interface Options { 2 | spacing?: boolean; 3 | seperator?: string; 4 | squareBracketsForArray?: boolean; 5 | doubleQuotesForKeys?: boolean; 6 | doubleQuotesForValues?: boolean; 7 | } 8 | /** 9 | * Convert JSON-like data or plain JavaScript objects to formatted plain text representation. 10 | */ 11 | declare function jsonToPlainText(data: unknown, options?: Options): string; 12 | export { jsonToPlainText, Options }; 13 | -------------------------------------------------------------------------------- /dist/esm/index.d.ts: -------------------------------------------------------------------------------- 1 | interface Options { 2 | spacing?: boolean; 3 | seperator?: string; 4 | squareBracketsForArray?: boolean; 5 | doubleQuotesForKeys?: boolean; 6 | doubleQuotesForValues?: boolean; 7 | } 8 | /** 9 | * Convert JSON-like data or plain JavaScript objects to formatted plain text representation. 10 | */ 11 | declare function jsonToPlainText(data: unknown, options?: Options): string; 12 | export { jsonToPlainText, Options }; 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: sumithemmadi 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: sumithemmadi 10 | # issuehunt: sumithemmadi 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://paypal.me/sumithemmadi"] 13 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Ignore source and test files 2 | src/ 3 | test/ 4 | 5 | # Ignore build configs 6 | tsconfig.json 7 | tsconfig.cjs.json 8 | jest.config.ts 9 | 10 | # Ignore environment/config files 11 | .eslintrc.json 12 | .eslintrc 13 | .eslintignore 14 | .prettierrc.json 15 | .prettierignore 16 | 17 | # Ignore VCS & GitHub files 18 | .gitignore 19 | .github/ 20 | 21 | # Ignore documentation (optional, keep README & LICENSE usually) 22 | CHANGELOG.md 23 | CODE_OF_CONDUCT.md 24 | SECURITY.md 25 | 26 | # Ignore lock files (optional, up to you) 27 | package-lock.json 28 | yarn.lock 29 | 30 | # Ignore misc 31 | *.log 32 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | permissions: 2 | contents: read 3 | name: JSON to plain text lib tests 4 | 5 | on: 6 | push: 7 | branches: [main] 8 | pull_request: 9 | branches: [main] 10 | 11 | jobs: 12 | test: 13 | runs-on: ubuntu-latest 14 | 15 | strategy: 16 | matrix: 17 | node-version: [18.x, 20.x] 18 | 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v4 22 | 23 | - name: Setup Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | 28 | - name: Install dependencies 29 | run: yarn install --no-lockfile 30 | 31 | - name: Run tests 32 | run: yarn test 33 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ES2020", 4 | "target": "ES2020", 5 | "outDir": "dist/esm", 6 | "rootDir": "src", 7 | "baseUrl": "src", 8 | "allowJs": true, 9 | "allowSyntheticDefaultImports": true, 10 | "esModuleInterop": true, 11 | "listEmittedFiles": false, 12 | "listFiles": false, 13 | "moduleResolution": "node", 14 | "pretty": true, 15 | "resolveJsonModule": true, 16 | "sourceMap": false, 17 | "declaration": true, 18 | "declarationMap": false, 19 | "forceConsistentCasingInFileNames": true, 20 | "strict": true, 21 | "skipLibCheck": true, 22 | "typeRoots": ["./node_modules/@types"], 23 | "types": ["node"] 24 | }, 25 | "compileOnSave": true, 26 | "include": ["src/**/*.ts"], 27 | "exclude": ["node_modules", "dist"] 28 | } 29 | -------------------------------------------------------------------------------- /tsconfig.cjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "outDir": "dist/cjs", 6 | "rootDir": "src", 7 | "baseUrl": "src", 8 | "allowJs": true, 9 | "allowSyntheticDefaultImports": true, 10 | "esModuleInterop": true, 11 | "listEmittedFiles": false, 12 | "listFiles": false, 13 | "moduleResolution": "node", 14 | "pretty": true, 15 | "resolveJsonModule": true, 16 | "sourceMap": false, 17 | "declaration": true, 18 | "declarationMap": false, 19 | "forceConsistentCasingInFileNames": true, 20 | "strict": true, 21 | "skipLibCheck": true, 22 | "typeRoots": ["./node_modules/@types"], 23 | "types": ["node"] 24 | }, 25 | "compileOnSave": true, 26 | "include": ["src/**/*.ts"], 27 | "exclude": ["node_modules", "dist"] 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Emmadi Sumith Kumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is based on [Keep a Changelog](http://keepachangelog.com/) 5 | and this project adheres to [Semantic Versioning](http://semver.org/). 6 | 7 | 8 | ## [1.2.0] - 2023-12-8 9 | 10 | - Removed coloring to support browsers. 11 | 12 | ## [1.1.4] - 2023-12-8 13 | 14 | - Fixed some mistakes. 15 | 16 | ### Changed 17 | 18 | - [json-to-plain-text](https://github.com/sumithemmadi/json-to-plain-text) Made some updates in readme, tsconfig.json and jest. 19 | 20 | ## [1.1.3] - 2023-08-30 21 | 22 | Here we write upgrading notes for brands. It's a team effort to make them as 23 | straightforward as possible. 24 | 25 | ### Added 26 | - [json-to-plain-text](https://github.com/sumithemmadi/json-to-plain-text) Added seperator option. 27 | 28 | ### Changed 29 | 30 | - [json-to-plain-text](https://github.com/sumithemmadi/json-to-plain-text) Made some updates 31 | 32 | 33 | ### Fixed 34 | - [json-to-plain-text](https://github.com/sumithemmadi/json-to-plain-text) interfaceof options `Options` is not exported. So , It is fixed in this version. 35 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | ## Supported Versions 2 | 3 | This section outlines the versions of the "json-to-plain-text" package that are currently eligible for receiving security updates and maintenance. It's essential to keep your software up to date to ensure the security and stability of your applications. 4 | 5 | | Version | Supported | Notes | 6 | | ----------- | ------------------ | ------------------------- | 7 | | 1.1.x | :white_check_mark: | Latest and actively maintained version. Security updates and bug fixes will be provided. It's recommended to upgrade to this version. | 8 | | 1.0.x | :x: | This version is no longer receiving security updates. Users are advised to upgrade to the latest 1.1.x release for continued support. | 9 | | < 1.0 | :x: | Versions prior to 1.0 are not supported and may contain known security vulnerabilities. Users should upgrade to a supported version. | 10 | 11 | It's our priority to provide a secure and reliable package for our users. We strongly encourage all users to stay up to date with the latest supported version to benefit from the latest security enhancements and bug fixes. 12 | 13 | ## Reporting a Vulnerability 14 | 15 | I take security vulnerabilities seriously and appreciate the help of the community in identifying and addressing them. If you discover a security vulnerability in the "json-to-plain-text" package, please report it: 16 | 17 | **Contact Information**: You can report the vulnerability by raiseing issue [json-to-plain-text](https://github.com/sumithemmadi/json-to-plain-text). Please provide a detailed description of the vulnerability and steps to reproduce it, if possible. 18 | 19 | 20 | Thank you for your dedication to the security of the "json-to-plain-text" package. Your responsible disclosure helps us provide a safer experience for all our users. 21 | -------------------------------------------------------------------------------- /test/index.test.js: -------------------------------------------------------------------------------- 1 | const { jsonToPlainText } = require("../dist/cjs/index.js"); 2 | 3 | describe("jsonToPlainText function", () => { 4 | test("should convert simple object to formatted plain text", () => { 5 | const data = { 6 | name: "John", 7 | age: 30, 8 | isEmployed: true, 9 | }; 10 | 11 | const expectedOutput = ` 12 | name = John 13 | age = 30 14 | isEmployed = true`; 15 | 16 | const result = jsonToPlainText(data, { color: false, seperator: "=" }); 17 | expect(result).toBe(expectedOutput); 18 | }); 19 | test("handles empty object", () => { 20 | expect(jsonToPlainText({})).toBe("{}"); 21 | }); 22 | 23 | test("handles empty array", () => { 24 | expect(jsonToPlainText([])).toBe("[]"); 25 | }); 26 | 27 | test("handles null and undefined", () => { 28 | expect(jsonToPlainText({ a: null, b: undefined })).toContain("a : null"); 29 | }); 30 | 31 | test("handles numbers, booleans, and strings", () => { 32 | const obj = { age: 25, active: true, name: "Sumith" }; 33 | const result = jsonToPlainText(obj, { doubleQuotesForValues: true }); 34 | expect(result).toContain(`"Sumith"`); 35 | }); 36 | 37 | test("handles dates", () => { 38 | const date = new Date("2020-01-01T00:00:00Z"); 39 | const result = jsonToPlainText({ d: date }); 40 | expect(result).toContain("2020-01-01T00:00:00.000Z"); 41 | }); 42 | 43 | test("handles regex", () => { 44 | const result = jsonToPlainText({ pattern: /abc/g }); 45 | expect(result).toContain("/abc/g"); 46 | }); 47 | 48 | test("handles functions", () => { 49 | const result = jsonToPlainText({ fn: () => {} }); 50 | expect(result).toContain("[object Function]"); 51 | }); 52 | 53 | test("handles circular references", () => { 54 | const obj = {}; 55 | obj.self = obj; 56 | const result = jsonToPlainText(obj); 57 | expect(result).toContain("[Circular]"); 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-to-plain-text", 3 | "version": "1.2.0", 4 | "description": "Convert JSON or JavaScript objects into clean, human-readable plain text format.", 5 | "main": "./dist/cjs/index.js", 6 | "module": "./dist/esm/index.js", 7 | "type": "module", 8 | "exports": { 9 | ".": { 10 | "import": "./dist/esm/index.js", 11 | "require": "./dist/cjs/index.js" 12 | }, 13 | "./package.json": "./package.json" 14 | }, 15 | "types": "./dist/esm/index.d.ts", 16 | "scripts": { 17 | "build": "rm -rf dist && tsc && npm run build:cjs", 18 | "build:cjs": "tsc --project tsconfig.cjs.json && npm run echo:type-cjs", 19 | "echo:type-cjs": "echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json", 20 | "test": "jest --passWithNoTests", 21 | "eslint": "npx eslint .", 22 | "prettier": "npx prettier --write .", 23 | "prepare": "npm run build" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/sumithemmadi/json-to-plain-text.git" 28 | }, 29 | "keywords": [ 30 | "json", 31 | "plain text", 32 | "json to text", 33 | "json formatter", 34 | "json pretty print", 35 | "formatter", 36 | "logging", 37 | "debugging", 38 | "cli", 39 | "output", 40 | "print", 41 | "human readable", 42 | "node", 43 | "nodejs", 44 | "typescript", 45 | "utility" 46 | ], 47 | "author": "sumithemmadi", 48 | "license": "MIT", 49 | "bugs": { 50 | "url": "https://github.com/sumithemmadi/json-to-plain-text/issues" 51 | }, 52 | "homepage": "https://github.com/sumithemmadi/json-to-plain-text#readme", 53 | "devDependencies": { 54 | "@types/node": "^20.4.2", 55 | "@typescript-eslint/eslint-plugin": "^6.1.0", 56 | "@typescript-eslint/parser": "^6.1.0", 57 | "eslint": "^8.45.0", 58 | "jest": "^29.6.1", 59 | "prettier": "^3.0.0", 60 | "ts-node": "^10.9.1", 61 | "typescript": "^5.1.6" 62 | }, 63 | "files": [ 64 | "dist", 65 | "README.md", 66 | "LICENSE" 67 | ], 68 | "sideEffects": false 69 | } 70 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct for https://github.com/sumithemmadi/json-to-plain-text 2 | 3 | ## Our Pledge 4 | 5 | We, as members, contributors, and maintainers of this repository, pledge to foster an open, inclusive, and respectful environment for everyone who engages with our project. We are dedicated to providing a harassment-free experience, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to a positive environment include: 10 | 11 | - Being respectful and considerate towards others. 12 | - Encouraging and supporting each other's ideas and contributions. 13 | - Providing and receiving constructive feedback with grace and openness. 14 | - Being empathetic and understanding towards differing perspectives. 15 | 16 | Examples of unacceptable behavior include: 17 | 18 | - Use of offensive, derogatory, or inappropriate language. 19 | - Harassment, trolling, or any form of personal attacks. 20 | - Publishing private information without explicit permission. 21 | - Engaging in any behavior that could be considered inappropriate or harmful. 22 | 23 | ## Responsibilities 24 | 25 | Project maintainers are responsible for upholding the standards of conduct within the repository. They have the right and duty to remove, edit, or reject comments, code, and other contributions that violate this Code of Conduct. 26 | 27 | ## Scope 28 | 29 | This Code of Conduct applies to all interactions within the repository, as well as to any public representation of the project. This includes comments, issues, pull requests, code reviews, and any other communication. 30 | 31 | ## Enforcement 32 | 33 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [Your Contact Email]. All complaints will be reviewed promptly and treated with confidentiality and respect. Project maintainers are obligated to respect the privacy and security of the reporter of any incident. 34 | 35 | ## Consequences 36 | 37 | Anyone found to be violating this Code of Conduct may face consequences, which can include: 38 | 39 | 1. **Warning**: A private, written warning from the project maintainers. 40 | 2. **Temporary Ban**: A temporary ban from participating in the repository. 41 | 3. **Permanent Ban**: A permanent ban from the repository and its related activities. 42 | 43 | Project maintainers will use their discretion in determining the appropriate consequences for each case, considering the severity and impact of the violation. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json-to-plain-text 2 | 3 | [![Version](https://img.shields.io/npm/v/json-to-plain-text.svg)](https://www.npmjs.com/package/json-to-plain-text) 4 | [![Stars](https://img.shields.io/github/stars/sumithemmadi/json-to-plain-text)](https://github.com/sumithemmadi/json-to-plain-text/stargazers) 5 | [![Downloads](https://img.shields.io/npm/dt/json-to-plain-text.svg)](https://www.npmjs.com/package/json-to-plain-text) 6 | [![License](https://img.shields.io/npm/l/json-to-plain-text.svg)](LICENSE) 7 | [![Maintenance](https://img.shields.io/npms-io/maintenance-score/json-to-plain-text)](https://github.com/sumithemmadi/json-to-plain-text) 8 | [![Issues](https://img.shields.io/github/issues/sumithemmadi/json-to-plain-text)](https://github.com/sumithemmadi/json-to-plain-text/issues) 9 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/sumithemmadi)](https://github.com/sponsors/sumithemmadi) 10 | [![Install size](https://img.shields.io/badge/dynamic/json?url=https://packagephobia.com/v2/api.json?p=json-to-plain-text&query=$.install.pretty&label=install%20size)](https://packagephobia.com/result?p=json-to-plain-text) 11 | [![Bundle size](https://img.shields.io/bundlephobia/minzip/json-to-plain-text)](https://bundlephobia.com/package/json-to-plain-text@latest) 12 | [![Known Vulnerabilities](https://snyk.io/test/npm/json-to-plain-text/badge.svg)](https://snyk.io/test/npm/json-to-plain-text) 13 | 14 | --- 15 | 16 | ## 📖 Overview 17 | 18 | `json-to-plain-text` is a lightweight npm package that converts **JSON** into a clean, human-readable **plain-text**. 19 | 20 | Think of it as `JSON.stringify()`, but prettier, friendlier, and tailored for **logs, debugging, and CLI output**. 21 | 22 | > [!NOTE] 23 | > From version **2.0.0+**, this package outputs plain text only. 24 | > If you need **colored output**, please use [version 1.1.4](https://www.npmjs.com/package/json-to-plain-text/v/1.1.4) . 25 | 26 | --- 27 | 28 | ## ✨ Features 29 | 30 | - 🔹 Convert JSON objects into easy-to-read plain text 31 | - ⚡ Tiny & fast (zero dependencies) 32 | - 🛠 Configurable separators, spacing, quotes, and array formatting 33 | - ✅ Great for **logs, debugging, reports, and CLI tools** 34 | 35 | --- 36 | 37 | ## 🔍 Why use this? 38 | 39 | Use `json-to-plain-text` when you need: 40 | - 📑 **Readable logs** – no more squinting at raw JSON 41 | - 🖥 **CLI outputs** – format objects neatly for the terminal 42 | - 🧪 **Debugging helpers** – quickly inspect nested objects 43 | - 📝 **Reports/configs** – human-friendly data printing 44 | 45 | --- 46 | 47 | ## 🚀 Installation 48 | 49 | ```bash 50 | npm install json-to-plain-text 51 | ``` 52 | 53 | --- 54 | 55 | ## 📦 Usage 56 | 57 | ```js 58 | import { jsonToPlainText } from "json-to-plain-text"; 59 | ``` 60 | 61 | --- 62 | 63 | ## ⚙️ API 64 | 65 | ```ts 66 | jsonToPlainText(data: unknown, options?: Options): string 67 | ``` 68 | 69 | ### Parameters 70 | 71 | - **`data`** *(required)* – JSON-like input or JavaScript object. 72 | - **`options`** *(optional)* – Customize the formatting. 73 | 74 | | Option | Type | Default | Description | 75 | |---------------------------|---------|---------|-------------| 76 | | `separator` | string | `:` | Character used between keys and values. | 77 | | `spacing` | boolean | `true` | Align keys with spacing before colons. | 78 | | `squareBracketsForArray` | boolean | `false` | Display arrays inside `[]`. | 79 | | `doubleQuotesForKeys` | boolean | `false` | Wrap object keys in double quotes. | 80 | | `doubleQuotesForValues` | boolean | `false` | Wrap string values in double quotes. | 81 | 82 | --- 83 | 84 | ## 💡 Example 85 | 86 | ```ts 87 | import { jsonToPlainText, Options } from "json-to-plain-text"; 88 | 89 | const data = { 90 | place_id: "173937105", 91 | osm_type: "way", 92 | lat: "17.861533866867224", 93 | lon: "78.8081441896764", 94 | address: { 95 | city: "Hyderabad", 96 | state: "Telangana", 97 | country: "India", 98 | }, 99 | distance: 2, 100 | }; 101 | 102 | const options: Options = { 103 | separator: ":", 104 | spacing: true, 105 | squareBracketsForArray: false, 106 | doubleQuotesForKeys: false, 107 | doubleQuotesForValues: false, 108 | }; 109 | 110 | console.log(jsonToPlainText(data, options)); 111 | ``` 112 | 113 | ### ✅ Output 114 | 115 | ```yaml 116 | place_id : 173937105 117 | osm_type : way 118 | lat : 17.861533866867224 119 | lon : 78.8081441896764 120 | address : 121 | city : Hyderabad 122 | state : Telangana 123 | country : India 124 | distance : 2 125 | ``` 126 | 127 | --- 128 | 129 | ## 💝 Support 130 | 131 | If this project helps you, consider supporting my open-source work: 132 | 133 | - [💖 SPONSOR ME ON GITHUB](https://github.com/sponsors/sumithemmadi?o=sd&sc=t) 134 | 135 | A huge thanks to all sponsors for supporting my work! 136 | 137 | --- 138 | 139 | ## 📜 License 140 | 141 | This project is licensed under the [MIT License](LICENSE). 142 | 143 | --- 144 | 145 | ## 👨‍💻 Author 146 | 147 | - [Sumith Emmadi](https://github.com/sumithemmadi) 148 | -------------------------------------------------------------------------------- /dist/esm/index.js: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // Copyright (c) 2021 Emmadi Sumith Kumar 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // The above copyright notice and this permission notice shall be included in all 10 | // copies or substantial portions of the Software. 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | // SOFTWARE. 18 | /** 19 | * Convert JSON-like data or plain JavaScript objects to formatted plain text representation. 20 | */ 21 | function jsonToPlainText(data, options) { 22 | const visited = new Set(); 23 | let indentLevel = 1; 24 | const defaultOptions = { 25 | spacing: true, 26 | seperator: ":", 27 | squareBracketsForArray: false, 28 | doubleQuotesForKeys: false, 29 | doubleQuotesForValues: false, 30 | }; 31 | const outputOptions = { ...defaultOptions, ...options }; 32 | // Helper function to determine the type of a variable 33 | function getType(variable) { 34 | const type = typeof variable; 35 | if (type === "object") { 36 | if (variable === null) 37 | return "null"; 38 | if (Array.isArray(variable)) 39 | return "array"; 40 | if (variable instanceof Date) 41 | return "date"; 42 | if (variable instanceof RegExp) 43 | return "regexp"; 44 | return "object"; 45 | } 46 | return type; 47 | } 48 | // Helper function to handle arrays 49 | function handleArray(arr) { 50 | if (arr.length === 0) 51 | return "[]"; 52 | const output = arr 53 | .map((item) => { 54 | const handler = handlers[getType(item)]; 55 | if (!handler) 56 | throw new Error("Unsupported data type: " + getType(item)); 57 | return handler(item, true); 58 | }) 59 | .join(", "); 60 | return outputOptions.squareBracketsForArray ? `[ ${output} ]` : output; 61 | } 62 | // Helper function to handle objects 63 | function handleObject(obj) { 64 | if (Object.keys(obj).length === 0) 65 | return "{}"; 66 | let output = ""; 67 | Object.keys(obj).forEach((key) => { 68 | const value = obj[key]; 69 | if (typeof value === "undefined") 70 | return; 71 | const handler = handlers[getType(value)]; 72 | if (!handler) 73 | throw new Error("Unsupported data type: " + getType(value)); 74 | if (key.length >= indentLevel) 75 | indentLevel = key.length; 76 | output += 77 | "\n" + 78 | (outputOptions.doubleQuotesForKeys ? `"${key}"` : key) + 79 | "}json-to-plain-text-special-string-" + 80 | key.length + 81 | "{" + 82 | handler(value, true); 83 | }); 84 | return output; 85 | } 86 | // Handlers for different data types 87 | const handlers = { 88 | undefined: () => "undefined", 89 | null: () => "null", 90 | number: (x) => x.toString(), 91 | boolean: (x) => (x ? "true" : "false"), 92 | string: (x) => (outputOptions.doubleQuotesForValues ? `"${x}"` : x), 93 | array: (x) => { 94 | if (visited.has(x)) 95 | return "[Circular]"; 96 | visited.add(x); 97 | const output = handleArray(x); 98 | visited.delete(x); 99 | return output; 100 | }, 101 | object: (x) => { 102 | if (visited.has(x)) 103 | return "[Circular]"; 104 | visited.add(x); 105 | const output = handleObject(x); 106 | visited.delete(x); 107 | return output; 108 | }, 109 | date: (x) => x.toISOString(), 110 | regexp: (x) => x.toString(), 111 | function: () => "[object Function]", 112 | }; 113 | return handlers[getType(data)](data, false).replace(/}json-to-plain-text-special-string-(\d+){/g, (match, number) => { 114 | const space = parseInt(number, 10); 115 | return outputOptions.spacing 116 | ? " ".repeat(indentLevel - space) + ` ${outputOptions.seperator} ` 117 | : ` ${outputOptions.seperator} `; 118 | }); 119 | } 120 | export { jsonToPlainText }; 121 | -------------------------------------------------------------------------------- /dist/cjs/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // MIT License 3 | // Copyright (c) 2021 Emmadi Sumith Kumar 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // The above copyright notice and this permission notice shall be included in all 11 | // copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 18 | // SOFTWARE. 19 | Object.defineProperty(exports, "__esModule", { value: true }); 20 | exports.jsonToPlainText = jsonToPlainText; 21 | /** 22 | * Convert JSON-like data or plain JavaScript objects to formatted plain text representation. 23 | */ 24 | function jsonToPlainText(data, options) { 25 | const visited = new Set(); 26 | let indentLevel = 1; 27 | const defaultOptions = { 28 | spacing: true, 29 | seperator: ":", 30 | squareBracketsForArray: false, 31 | doubleQuotesForKeys: false, 32 | doubleQuotesForValues: false, 33 | }; 34 | const outputOptions = { ...defaultOptions, ...options }; 35 | // Helper function to determine the type of a variable 36 | function getType(variable) { 37 | const type = typeof variable; 38 | if (type === "object") { 39 | if (variable === null) 40 | return "null"; 41 | if (Array.isArray(variable)) 42 | return "array"; 43 | if (variable instanceof Date) 44 | return "date"; 45 | if (variable instanceof RegExp) 46 | return "regexp"; 47 | return "object"; 48 | } 49 | return type; 50 | } 51 | // Helper function to handle arrays 52 | function handleArray(arr) { 53 | if (arr.length === 0) 54 | return "[]"; 55 | const output = arr 56 | .map((item) => { 57 | const handler = handlers[getType(item)]; 58 | if (!handler) 59 | throw new Error("Unsupported data type: " + getType(item)); 60 | return handler(item, true); 61 | }) 62 | .join(", "); 63 | return outputOptions.squareBracketsForArray ? `[ ${output} ]` : output; 64 | } 65 | // Helper function to handle objects 66 | function handleObject(obj) { 67 | if (Object.keys(obj).length === 0) 68 | return "{}"; 69 | let output = ""; 70 | Object.keys(obj).forEach((key) => { 71 | const value = obj[key]; 72 | if (typeof value === "undefined") 73 | return; 74 | const handler = handlers[getType(value)]; 75 | if (!handler) 76 | throw new Error("Unsupported data type: " + getType(value)); 77 | if (key.length >= indentLevel) 78 | indentLevel = key.length; 79 | output += 80 | "\n" + 81 | (outputOptions.doubleQuotesForKeys ? `"${key}"` : key) + 82 | "}json-to-plain-text-special-string-" + 83 | key.length + 84 | "{" + 85 | handler(value, true); 86 | }); 87 | return output; 88 | } 89 | // Handlers for different data types 90 | const handlers = { 91 | undefined: () => "undefined", 92 | null: () => "null", 93 | number: (x) => x.toString(), 94 | boolean: (x) => (x ? "true" : "false"), 95 | string: (x) => (outputOptions.doubleQuotesForValues ? `"${x}"` : x), 96 | array: (x) => { 97 | if (visited.has(x)) 98 | return "[Circular]"; 99 | visited.add(x); 100 | const output = handleArray(x); 101 | visited.delete(x); 102 | return output; 103 | }, 104 | object: (x) => { 105 | if (visited.has(x)) 106 | return "[Circular]"; 107 | visited.add(x); 108 | const output = handleObject(x); 109 | visited.delete(x); 110 | return output; 111 | }, 112 | date: (x) => x.toISOString(), 113 | regexp: (x) => x.toString(), 114 | function: () => "[object Function]", 115 | }; 116 | return handlers[getType(data)](data, false).replace(/}json-to-plain-text-special-string-(\d+){/g, (match, number) => { 117 | const space = parseInt(number, 10); 118 | return outputOptions.spacing 119 | ? " ".repeat(indentLevel - space) + ` ${outputOptions.seperator} ` 120 | : ` ${outputOptions.seperator} `; 121 | }); 122 | } 123 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | // MIT License 2 | // Copyright (c) 2021 Emmadi Sumith Kumar 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // The above copyright notice and this permission notice shall be included in all 10 | // copies or substantial portions of the Software. 11 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | // SOFTWARE. 18 | 19 | interface Options { 20 | spacing?: boolean; // Whether to include spacing after colons or not 21 | seperator?: string; // seperator. Default ':', 22 | squareBracketsForArray?: boolean; // Whether to use square brackets for arrays or not 23 | doubleQuotesForKeys?: boolean; // Whether to use double quotes for object keys or not 24 | doubleQuotesForValues?: boolean; // Whether to use double quotes for string values or not 25 | } 26 | 27 | /** 28 | * Convert JSON-like data or plain JavaScript objects to formatted plain text representation. 29 | */ 30 | function jsonToPlainText(data: unknown, options?: Options): string { 31 | const visited = new Set(); 32 | let indentLevel = 1; 33 | 34 | const defaultOptions: Options = { 35 | spacing: true, 36 | seperator: ":", 37 | squareBracketsForArray: false, 38 | doubleQuotesForKeys: false, 39 | doubleQuotesForValues: false, 40 | }; 41 | 42 | const outputOptions = { ...defaultOptions, ...options }; 43 | 44 | // Helper function to determine the type of a variable 45 | function getType(variable: unknown): string { 46 | const type = typeof variable; 47 | if (type === "object") { 48 | if (variable === null) return "null"; 49 | if (Array.isArray(variable)) return "array"; 50 | if (variable instanceof Date) return "date"; 51 | if (variable instanceof RegExp) return "regexp"; 52 | return "object"; 53 | } 54 | return type; 55 | } 56 | 57 | // Helper function to handle arrays 58 | function handleArray(arr: unknown[]): string { 59 | if (arr.length === 0) return "[]"; 60 | 61 | const output = arr 62 | .map((item) => { 63 | const handler = handlers[getType(item)]; 64 | if (!handler) 65 | throw new Error("Unsupported data type: " + getType(item)); 66 | return handler(item, true); 67 | }) 68 | .join(", "); 69 | 70 | return outputOptions.squareBracketsForArray ? `[ ${output} ]` : output; 71 | } 72 | 73 | // Helper function to handle objects 74 | function handleObject(obj: { [key: string]: unknown }): string { 75 | if (Object.keys(obj).length === 0) return "{}"; 76 | 77 | let output = ""; 78 | Object.keys(obj).forEach((key) => { 79 | const value = obj[key]; 80 | if (typeof value === "undefined") return; 81 | const handler = handlers[getType(value)]; 82 | if (!handler) throw new Error("Unsupported data type: " + getType(value)); 83 | if (key.length >= indentLevel) indentLevel = key.length; 84 | 85 | output += 86 | "\n" + 87 | (outputOptions.doubleQuotesForKeys ? `"${key}"` : key) + 88 | "}json-to-plain-text-special-string-" + 89 | key.length + 90 | "{" + 91 | handler(value, true); 92 | }); 93 | return output; 94 | } 95 | 96 | // Handlers for different data types 97 | const handlers: { 98 | [key: string]: (data: any, inArray: boolean) => string; 99 | } = { 100 | undefined: () => "undefined", 101 | null: () => "null", 102 | number: (x: number) => x.toString(), 103 | boolean: (x: boolean) => (x ? "true" : "false"), 104 | string: (x: string) => (outputOptions.doubleQuotesForValues ? `"${x}"` : x), 105 | array: (x: unknown[]) => { 106 | if (visited.has(x)) return "[Circular]"; 107 | visited.add(x); 108 | const output = handleArray(x); 109 | visited.delete(x); 110 | return output; 111 | }, 112 | object: (x: { [key: string]: unknown }) => { 113 | if (visited.has(x)) return "[Circular]"; 114 | visited.add(x); 115 | const output = handleObject(x); 116 | visited.delete(x); 117 | return output; 118 | }, 119 | date: (x: Date) => x.toISOString(), 120 | regexp: (x: RegExp) => x.toString(), 121 | function: () => "[object Function]", 122 | }; 123 | 124 | return handlers[getType(data)](data, false).replace( 125 | /}json-to-plain-text-special-string-(\d+){/g, 126 | (match, number) => { 127 | const space = parseInt(number, 10); 128 | return outputOptions.spacing 129 | ? " ".repeat(indentLevel - space) + ` ${outputOptions.seperator} ` 130 | : ` ${outputOptions.seperator} `; 131 | }, 132 | ); 133 | } 134 | 135 | export { jsonToPlainText, Options }; 136 | --------------------------------------------------------------------------------