npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tally-clean-response

v1.2.1

Published

Clean, sanitize, and normalize raw JSON from Tally ERP 9 and TallyPrime XML responses into plain JavaScript objects

Readme

tally-clean-response

npm version License: MIT Zero Dependencies Node.js TypeScript

Lightweight, zero-dependency utility to clean, sanitize, and normalize JSON responses from Tally ERP 9 / TallyPrime XML-to-JSON parsers into clean, developer-friendly JavaScript objects.

🌐 Live Documentation • 📖 Architecture Guide (or offline markdown) • 💡 Examples & Recipes • 📦 npm package


Overview

When querying Tally via XML/TDL (using libraries like tally-to-xml-tdl or fast-xml-parser), the parsed JSON contains heavy XML serialization artifacts:

  • Typed wrappers: Scalar values wrapped in type metadata objects, e.g. {"@_TYPE": "String", "#text": "Pur Exp"} or {"@_TYPE": "Number", "#text": 1}.
  • Empty tag noise: Empty XML nodes like <ALLINVENTORYENTRIES.LIST TYPE="String"/> converted into { "@_TYPE": "String" } instead of clean empty values.
  • Deep nesting: Collection records trapped inside ENVELOPE.BODY.DATA.COLLECTION.*.
  • Inconsistent single-item collections: Tally returns a single object instead of an array when only one item matches.

tally-clean-response automates this cleanup in a single call, returning a normalized array of pristine JavaScript objects with full recursive unwrapping of all nested inventory and ledger lines.


Comparison: Before vs After

❌ Raw Parsed Tally XML Output (Before)

{
  "ENVELOPE": {
    "HEADER": { "TALLYREQUEST": "Export Data" },
    "BODY": {
      "DATA": {
        "COLLECTION": {
          "VOUCHER": [
            {
              "DATE": { "@_TYPE": "Date", "#text": "20260401" },
              "GUID": "56b158ca-11af-4ad5-bc28-c1c2428041b9-0002a874",
              "VOUCHERTYPENAME": { "@_TYPE": "String", "#text": "Pur Exp" },
              "VOUCHERNUMBER": { "@_TYPE": "Number", "#text": 1 },
              "ISDEEMEDPOSITIVE": { "@_TYPE": "Logical", "#text": "No" },
              "ALLINVENTORYENTRIES.LIST": { "@_TYPE": "String" },
              "@_REMOTEID": "56b158ca-11af-4ad5-bc28-c1c2428041b9-0002a874",
              "@_VCHKEY": "56b158ca-11af-4ad5-bc28-c1c2428041b9-0000b420:000000a8"
            }
          ]
        }
      }
    }
  }
}

✅ Cleaned Response (After cleanTallyResponse)

[
  {
    "DATE": "20260401",
    "GUID": "56b158ca-11af-4ad5-bc28-c1c2428041b9-0002a874",
    "VOUCHERTYPENAME": "Pur Exp",
    "VOUCHERNUMBER": 1,
    "ISDEEMEDPOSITIVE": "No",
    "ALLINVENTORYENTRIES.LIST": "",
    "@_REMOTEID": "56b158ca-11af-4ad5-bc28-c1c2428041b9-0002a874",
    "@_VCHKEY": "56b158ca-11af-4ad5-bc28-c1c2428041b9-0000b420:000000a8"
  }
]

Key Features

  • Zero Runtime Dependencies: Ultra-lightweight and fast, no bloat.
  • Deep Recursive Traversal: Cleans nested lists arbitrarily deep (ALLINVENTORYENTRIES.LIST, BATCHALLOCATIONS.LIST, LEDGERENTRIES.LIST, etc.).
  • Automatic Unboxing: Extracts #text values from typed leaf objects (String, Date, Number, Logical, Rate, Amount, etc.).
  • Tag Normalization: Unwraps empty typed nodes <TAG TYPE="..."/> to clean "" empty strings.
  • Collection Array Guarantee: Guarantees an array output even if Tally returns a single object.
  • Preserves Metadata Identifiers: Retains essential Tally attributes (e.g. @_REMOTEID, @_VCHKEY, @_VCHTYPE).
  • ESM & TypeScript Native: Full ESM support with bundled TypeScript declarations (index.d.ts).

Installation

npm install tally-clean-response

Or using pnpm / yarn:

pnpm add tally-clean-response
# or
yarn add tally-clean-response

Quick Start

1. Integration with tally-to-xml-tdl

import { vouchers } from "tally-to-xml-tdl";
import cleanTallyResponse from "tally-clean-response";

// 1. Fetch raw response from Tally
const rawData = await vouchers.purchases.period("MyCompany", "1-Apr-2026", "6-Apr-2026");

// 2. Clean the response
const cleanedVouchers = cleanTallyResponse(rawData);

console.log(`Fetched ${cleanedVouchers.length} vouchers:`);
console.log(cleanedVouchers[0]);

2. Usage with fast-xml-parser

import { XMLParser } from "fast-xml-parser";
import cleanTallyResponse from "tally-clean-response";

const parser = new XMLParser({
  ignoreAttributes: false,
  attributeNamePrefix: "@_",
  textNodeName: "#text"
});

const rawJson = parser.parse(tallyXmlString);
const records = cleanTallyResponse(rawJson);

Import Options

You can import either the default export or named export:

// Default import
import cleanTallyResponse from "tally-clean-response";

// Named import
import { cleanTallyResponse } from "tally-clean-response";

// Internal alias
import { startFunc } from "tally-clean-response";

// Subpath imports (if targeting a specific engine version)
import cleanTallyResponseV2 from "tally-clean-response/v2";
import cleanTallyResponseV1 from "tally-clean-response/v1";

Type Conversion Matrix

When unwrapping leaf nodes with @_TYPE:

| Tally @_TYPE Attribute | Sample Raw Input | Cleaned Output | Normalized Type | |---|---|---|---| | String | {"@_TYPE": "String", "#text": "Sales"} | "Sales" | string | | Date | {"@_TYPE": "Date", "#text": "20260401"} | "20260401" | string | | Logical | {"@_TYPE": "Logical", "#text": "Yes"} | "Yes" | string | | Rate | {"@_TYPE": "Rate", "#text": "500/Nos"} | "500/Nos" | string | | Number | {"@_TYPE": "Number", "#text": 125} | 125 | number | | Amount | {"@_TYPE": "Amount", "#text": 15000.5} | 15000.5 | number / string | | Quantity | {"@_TYPE": "Quantity", "#text": 10} | 10 | number / string | | Empty tag | {"@_TYPE": "String"} (no #text) | "" | string |

Attributes prefixed with @_ (such as @_REMOTEID, @_VCHKEY, @_VCHTYPE) that are attached directly to objects are preserved intact.


TypeScript Support

Full TypeScript definitions are included out-of-the-box. You can pass a generic type to cleanTallyResponse<T> for strong type safety:

import cleanTallyResponse from "tally-clean-response";

interface VoucherRow {
  DATE: string;
  GUID: string;
  VOUCHERTYPENAME: string;
  VOUCHERNUMBER: number;
  [key: string]: any;
}

const cleaned = cleanTallyResponse<VoucherRow>(tallyRawResponse);
// cleaned has type VoucherRow[]

API Reference

cleanTallyResponse(json)

function cleanTallyResponse<T = Record<string, any>>(json: any): T[];

Parameters

  • json (object): The parsed JSON object representing Tally XML output. Typically contains ENVELOPE.BODY.DATA.COLLECTION.

Return Value

  • Array<T>: An array of cleaned row objects.
  • If the collection contains a single record, it is returned inside a single-element array [record].
  • If no valid collection array or object is found, it returns the unwrapped rows or fallback data safely.

Project Structure

tally-clean-response/
├── src/
│   ├── index.js                     # Root entry point (re-exports v2 default & named)
│   ├── v1/                          # v1 engine implementation
│   │   ├── index.js
│   │   └── changeType/v1/           # Traversal & scalar unwrapping logic
│   └── v2/                          # v2 engine implementation (active)
│       ├── index.js
│       └── changeType/v1/
│           ├── alterLeaf.js         # Normalizes typed leaf nodes
│           ├── changeTypeString.js  # Collection traversal entry
│           ├── guards.js            # Type inspection utilities
│           ├── traverse.js          # Central recursive dispatcher
│           ├── forArray/v1/         # Array element mapping
│           └── forObject/v1/        # Object key/value mapping
├── docs/
│   ├── ARCHITECTURE.md              # Detailed traversal architecture guide
│   └── EXAMPLES.md                  # Comprehensive real-world examples
├── Test/                            # Test fixtures and execution scripts
├── index.d.ts                       # TypeScript declaration file
├── package.json
├── CHANGELOG.md
└── LICENSE

Related Projects

  • tally-to-xml-tdl: XML and TDL generator and client for querying Tally ERP 9 / TallyPrime.

License

MIT © 2026 KeshavSoft