feat(csv): add typed CSV APIs and modernize package configuration
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"@ship.zone/szci": {
|
||||||
|
"npmGlobalTools": [],
|
||||||
|
"npmRegistryUrl": "registry.npmjs.org"
|
||||||
|
},
|
||||||
|
"@git.zone/cli": {
|
||||||
|
"projectType": "npm",
|
||||||
|
"module": {
|
||||||
|
"githost": "code.foss.global",
|
||||||
|
"gitscope": "push.rocks",
|
||||||
|
"gitrepo": "smartcsv",
|
||||||
|
"shortDescription": "CSV parsing and serialization",
|
||||||
|
"description": "A module for handling CSV data compliant with Gitzone standard.",
|
||||||
|
"npmPackagename": "@push.rocks/smartcsv",
|
||||||
|
"license": "MIT",
|
||||||
|
"keywords": [
|
||||||
|
"CSV",
|
||||||
|
"data parsing",
|
||||||
|
"data conversion",
|
||||||
|
"TypeScript",
|
||||||
|
"CSV manipulation",
|
||||||
|
"CSV to JSON"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"registries": [
|
||||||
|
"https://verdaccio.lossless.digital",
|
||||||
|
"https://registry.npmjs.org"
|
||||||
|
],
|
||||||
|
"accessLevel": "public"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@git.zone/tsdoc": {
|
||||||
|
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.\n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.\n\nUse of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District Court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-05-02 - 2.1.0 - feat(csv)
|
||||||
|
add typed CSV APIs and modernize package configuration
|
||||||
|
|
||||||
|
- add explicit TypeScript types for CSV cell values, object rows, and parsed rows
|
||||||
|
- improve CSV string serialization by normalizing nullish values to empty strings
|
||||||
|
- modernize package metadata and tooling with exports, updated build/test dependencies, and stricter TypeScript settings
|
||||||
|
- replace file-based tests with inline node+chromium tests and add stronger parsing/string generation assertions
|
||||||
|
- refresh project documentation and add smart config metadata for release tooling
|
||||||
|
|
||||||
|
## 2026-03-01 - 2.0.2 - maintenance
|
||||||
|
Project maintenance updates were applied across the 2.0.2 line.
|
||||||
|
|
||||||
|
- Removed the GitLab CI configuration.
|
||||||
|
- Included assorted non-functional repository and metadata updates across 2023-07-10 to 2024-05-29, including org scheme changes, npm metadata adjustments, tsconfig updates, and description updates.
|
||||||
|
|
||||||
|
## 2022-10-29 - 2.0.2 - core
|
||||||
|
Small core fix release.
|
||||||
|
|
||||||
|
- Updated core behavior.
|
||||||
|
|
||||||
|
## 2022-08-06 - 2.0.1 - core
|
||||||
|
Small core fix release.
|
||||||
|
|
||||||
|
- Updated core behavior.
|
||||||
|
|
||||||
|
## 2022-08-06 - 2.0.0 - core
|
||||||
|
Major runtime update with a breaking module-system change.
|
||||||
|
|
||||||
|
- Switched to ESM.
|
||||||
|
- Enabled whitespace trimming by default.
|
||||||
|
- Includes the version publication for 2.0.0.
|
||||||
|
|
||||||
|
## 2022-01-03 - 1.0.23 - bom markers
|
||||||
|
Improved input handling for BOM-prefixed content.
|
||||||
|
|
||||||
|
- Now handles BOM markers correctly.
|
||||||
|
|
||||||
|
## 2019-12-15 - 1.0.22 - core
|
||||||
|
Patch releases focused on incremental fixes.
|
||||||
|
|
||||||
|
- Summarizes maintenance updates across versions 1.0.19 through 1.0.21, primarily minor core updates.
|
||||||
|
|
||||||
|
## 2018-10-14 - 1.0.15 - maintenance
|
||||||
|
A series of maintenance and internal quality improvements were released across versions 1.0.12 through 1.0.14.
|
||||||
|
|
||||||
|
- Refactored static function and constructor responsibilities.
|
||||||
|
- Ran project formatting and structural cleanup.
|
||||||
|
- Added Snyk policy support.
|
||||||
|
|
||||||
|
## 2018-08-18 - 1.0.11 - tooling
|
||||||
|
Tooling and CI improvements were released across versions 1.0.9 through 1.0.11.
|
||||||
|
|
||||||
|
- Updated testing configuration in CI.
|
||||||
|
- Refreshed dependencies.
|
||||||
|
- Removed an obsolete build dependency.
|
||||||
|
|
||||||
|
## 2018-06-10 - 1.0.8 - package
|
||||||
|
Packaging and maintenance updates were released across versions 1.0.6 through 1.0.8.
|
||||||
|
|
||||||
|
- Applied a minor core update.
|
||||||
|
- Removed unnecessary tool installs.
|
||||||
|
- Set the package private marker to false.
|
||||||
|
|
||||||
|
## 2018-05-10 - 1.0.5 - parser
|
||||||
|
Early releases introduced the initial feature set along with repository and packaging refinements.
|
||||||
|
|
||||||
|
- Added initial core implementation in 1.0.1.
|
||||||
|
- Added parser support for comma- and semicolon-separated CSV strings in 1.0.3.
|
||||||
|
- Included accompanying cleanup and maintenance updates across versions 1.0.2, 1.0.4, and 1.0.5.
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2019 Task Venture Capital GmbH <hello@task.vc>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
+13
-5
@@ -1,14 +1,15 @@
|
|||||||
{
|
{
|
||||||
"npmci": {
|
"@ship.zone/szci": {
|
||||||
"npmGlobalTools": [],
|
"npmGlobalTools": [],
|
||||||
"npmAccessLevel": "public"
|
"npmRegistryUrl": "registry.npmjs.org"
|
||||||
},
|
},
|
||||||
"gitzone": {
|
"@git.zone/cli": {
|
||||||
"projectType": "npm",
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "code.foss.global",
|
"githost": "code.foss.global",
|
||||||
"gitscope": "push.rocks",
|
"gitscope": "push.rocks",
|
||||||
"gitrepo": "smartcsv",
|
"gitrepo": "smartcsv",
|
||||||
|
"shortDescription": "CSV parsing and serialization",
|
||||||
"description": "A module for handling CSV data compliant with Gitzone standard.",
|
"description": "A module for handling CSV data compliant with Gitzone standard.",
|
||||||
"npmPackagename": "@push.rocks/smartcsv",
|
"npmPackagename": "@push.rocks/smartcsv",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@@ -20,9 +21,16 @@
|
|||||||
"CSV manipulation",
|
"CSV manipulation",
|
||||||
"CSV to JSON"
|
"CSV to JSON"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"registries": [
|
||||||
|
"https://verdaccio.lossless.digital",
|
||||||
|
"https://registry.npmjs.org"
|
||||||
|
],
|
||||||
|
"accessLevel": "public"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"tsdoc": {
|
"@git.zone/tsdoc": {
|
||||||
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository. \n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or if you require further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
"legal": "\n## License and Legal Information\n\nThis repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.\n\n**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.\n\n### Trademarks\n\nThis project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.\n\nUse of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.\n\n### Company Information\n\nTask Venture Capital GmbH \nRegistered at District Court Bremen HRB 35230 HB, Germany\n\nFor any legal inquiries or further information, please contact us via email at hello@task.vc.\n\nBy using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+13
-11
@@ -3,27 +3,27 @@
|
|||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "A module for handling CSV data compliant with Gitzone standard.",
|
"description": "A module for handling CSV data compliant with Gitzone standard.",
|
||||||
|
"exports": {
|
||||||
|
".": "./dist_ts/index.js"
|
||||||
|
},
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
"typings": "dist_ts/index.d.ts",
|
"typings": "dist_ts/index.d.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"author": "Lossless GmbH",
|
"author": "Task Venture Capital GmbH <hello@task.vc>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "(tstest test/)",
|
"test": "tstest test/",
|
||||||
"build": "(tsbuild --allowimplicitany)",
|
"build": "tsbuild",
|
||||||
"buildDocs": "tsdoc"
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.1.65",
|
"@git.zone/tsbuild": "^4.4.0",
|
||||||
"@gitzone/tsrun": "^1.2.37",
|
"@git.zone/tsdoc": "^2.0.3",
|
||||||
"@gitzone/tstest": "^1.0.73",
|
"@git.zone/tstest": "^3.6.3",
|
||||||
"@pushrocks/smartfile": "^10.0.4",
|
"@types/node": "^25.6.0"
|
||||||
"@pushrocks/tapbundle": "^5.0.4",
|
|
||||||
"@types/node": "^18.6.4"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pushrocks/smartpromise": "^3.1.7",
|
"@push.rocks/smartstring": "^4.1.1"
|
||||||
"@pushrocks/smartstring": "^4.0.2"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts/**/*",
|
"ts/**/*",
|
||||||
@@ -34,6 +34,8 @@
|
|||||||
"dist_ts_web/**/*",
|
"dist_ts_web/**/*",
|
||||||
"assets/**/*",
|
"assets/**/*",
|
||||||
"cli.js",
|
"cli.js",
|
||||||
|
".smartconfig.json",
|
||||||
|
"license",
|
||||||
"npmextra.json",
|
"npmextra.json",
|
||||||
"readme.md"
|
"readme.md"
|
||||||
],
|
],
|
||||||
|
|||||||
Generated
+7679
-3850
File diff suppressed because it is too large
Load Diff
@@ -1,118 +1,227 @@
|
|||||||
# @push.rocks/smartcsv
|
# @push.rocks/smartcsv
|
||||||
handle csv data | gitzone standard compliant
|
|
||||||
|
Small, typed CSV handling for TypeScript projects. `@push.rocks/smartcsv` turns CSV strings into object arrays, turns object arrays back into CSV strings, and keeps the API intentionally compact for browser and Node.js usage.
|
||||||
|
|
||||||
|
## Issue Reporting and Security
|
||||||
|
|
||||||
|
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
To install `@push.rocks/smartcsv`, use the following command with npm:
|
Use `pnpm` to add the package:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
npm install @push.rocks/smartcsv --save
|
pnpm add @push.rocks/smartcsv
|
||||||
```
|
```
|
||||||
|
|
||||||
Or, if you prefer using Yarn:
|
## What It Does
|
||||||
|
|
||||||
```sh
|
`@push.rocks/smartcsv` focuses on the common CSV workflows you usually need inside application code:
|
||||||
yarn add @push.rocks/smartcsv
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
- parse CSV text into typed JavaScript objects
|
||||||
|
- use the first CSV row as object keys
|
||||||
|
- auto-detect comma `,` or semicolon `;` separators
|
||||||
|
- handle quoted cells that contain separators
|
||||||
|
- optionally remove UTF-8 BOM markers
|
||||||
|
- optionally trim whitespace around headers and values
|
||||||
|
- serialize arrays of objects into CSV strings
|
||||||
|
|
||||||
`@push.rocks/smartcsv` is a powerful library designed for handling CSV data efficiently and in a developer-friendly manner. This document will guide you through various use cases and demonstrate the flexibility and capabilities of `@push.rocks/smartcsv`.
|
## Quick Start
|
||||||
|
|
||||||
### Importing the Module
|
```ts
|
||||||
|
|
||||||
First, import `Csv` from the `@push.rocks/smartcsv` package into your TypeScript file:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { Csv } from '@push.rocks/smartcsv';
|
import { Csv } from '@push.rocks/smartcsv';
|
||||||
|
|
||||||
|
const csvText = `name;role;city
|
||||||
|
"Ada Lovelace";"Mathematician";"London"
|
||||||
|
"Grace Hopper";"Computer scientist";"New York"`;
|
||||||
|
|
||||||
|
const csv = await Csv.createCsvFromString(csvText, {
|
||||||
|
headers: true,
|
||||||
|
unquote: true,
|
||||||
|
trimSpace: true,
|
||||||
|
removeBomMarkers: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = await csv.exportAsObject();
|
||||||
|
|
||||||
|
console.log(rows);
|
||||||
|
// [
|
||||||
|
// { name: 'Ada Lovelace', role: 'Mathematician', city: 'London' },
|
||||||
|
// { name: 'Grace Hopper', role: 'Computer scientist', city: 'New York' }
|
||||||
|
// ]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Creating a CSV Instance from a String
|
## Parsing CSV Strings
|
||||||
|
|
||||||
You can create a `Csv` instance directly from a string. This is particularly useful when you have CSV data as a string from a file or an API response:
|
Create a `Csv` instance with `Csv.createCsvFromString(csvString, options)`. The method prepares the parser and returns a reusable `Csv` instance.
|
||||||
|
|
||||||
```typescript
|
```ts
|
||||||
const csvString = `Name, Age, Occupation\nJohn Doe, 28, Software Developer\nJane Smith, 32, Data Scientist`;
|
import { Csv } from '@push.rocks/smartcsv';
|
||||||
|
|
||||||
const csvOptions = {
|
const csv = await Csv.createCsvFromString(
|
||||||
headers: true, // indicates the first row contains headers
|
'Product,Price,Available\nNotebook,12.5,true\nPen,1.2,true',
|
||||||
unquote: true, // unquote values if necessary
|
{
|
||||||
trimSpace: true, // trim spaces around values
|
headers: true,
|
||||||
removeBomMarkers: true // remove BOM markers if present
|
unquote: true,
|
||||||
};
|
trimSpace: true,
|
||||||
|
removeBomMarkers: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const csvInstance = await Csv.createCsvFromString(csvString, csvOptions);
|
const products = await csv.exportAsObject();
|
||||||
```
|
```
|
||||||
|
|
||||||
### Exporting CSV Data as JSON
|
Result:
|
||||||
|
|
||||||
Once you have a `Csv` instance, you can convert the CSV data into JSON objects for easier manipulation and access:
|
```ts
|
||||||
|
|
||||||
```typescript
|
|
||||||
const jsonData = await csvInstance.exportAsObject();
|
|
||||||
console.log(jsonData);
|
|
||||||
```
|
|
||||||
|
|
||||||
This will output:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
[
|
||||||
{ "Name": "John Doe", "Age": "28", "Occupation": "Software Developer" },
|
{ Product: 'Notebook', Price: '12.5', Available: 'true' },
|
||||||
{ "Name": "Jane Smith", "Age": "32", "Occupation": "Data Scientist" }
|
{ Product: 'Pen', Price: '1.2', Available: 'true' },
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Creating a CSV String from an Array of Objects
|
|
||||||
|
|
||||||
If you have an array of objects and wish to convert it into a CSV string, `@push.rocks/smartcsv` offers a straightforward approach:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const arrayOfObjects = [
|
|
||||||
{ Name: "John Doe", Age: 28, Occupation: "Software Developer" },
|
|
||||||
{ Name: "Jane Smith", Age: 32, Occupation: "Data Scientist" }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const csvString = await Csv.createCsvStringFromArray(arrayOfObjects);
|
|
||||||
console.log(csvString);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This will generate a CSV string that represents the array of objects provided.
|
Parsed values are returned as strings because CSV is a text format. Convert numbers, booleans, or dates in your application layer after parsing.
|
||||||
|
|
||||||
### Advanced Usage
|
## Parser Options
|
||||||
|
|
||||||
#### Custom Separator Detection
|
```ts
|
||||||
|
export interface ICsvConstructorOptions {
|
||||||
|
headers: boolean;
|
||||||
|
unquote?: boolean;
|
||||||
|
trimSpace?: boolean;
|
||||||
|
removeBomMarkers?: boolean;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
By default, `@push.rocks/smartcsv` intelligently detects the separator used in the input CSV data (either a comma `,` or a semicolon `;`). You can rely on this automatic detection or specify preferred options for finer control over how your CSV data is handled.
|
| Option | Default | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `headers` | required | When `true`, the first row is used as object keys. |
|
||||||
|
| `unquote` | `true` | Removes quotes from quoted headers and values. Quoted cells can contain separators. |
|
||||||
|
| `trimSpace` | `true` | Trims leading and trailing whitespace from headers and values. |
|
||||||
|
| `removeBomMarkers` | `true` | Removes a UTF-8 BOM marker from the beginning of the input string. |
|
||||||
|
|
||||||
#### Handling Quotes and BOM Markers
|
## Separator Detection
|
||||||
|
|
||||||
The library is capable of processing CSV files that include quoted fields, optionally removing quotes where necessary. Similarly, it can handle Byte Order Mark (BOM) markers at the start of UTF-8 encoded files, ensuring that the text is interpreted correctly.
|
The parser counts commas and semicolons in the input and uses the more common separator. If both appear equally often, comma is used.
|
||||||
|
|
||||||
#### Trimming Spaces
|
```ts
|
||||||
|
const semicolonCsv = await Csv.createCsvFromString('a;b\n1;2', {
|
||||||
|
headers: true,
|
||||||
|
});
|
||||||
|
|
||||||
For data cleanliness, `@push.rocks/smartcsv` can trim leading and trailing spaces from values in the CSV, ensuring that the resulting data is neat and uniform.
|
console.log(semicolonCsv.keyFrame); // ';'
|
||||||
|
```
|
||||||
|
|
||||||
### Conclusion
|
## Quoted Cells
|
||||||
|
|
||||||
`@push.rocks/smartcsv` offers a comprehensive set of features for working with CSV data in TypeScript, providing flexibility, ease of use, and powerful data manipulation capabilities. Whether you're importing CSV data from a file, converting JSON to CSV, or manipulating CSV strings directly in your application, `@push.rocks/smartcsv` has you covered.
|
With `unquote: true`, quoted values are protected before splitting rows. This allows separators inside quoted cells:
|
||||||
|
|
||||||
For detailed API documentation, please refer to the [official documentation](https://pushrocks.gitlab.io/smartcsv/).
|
```ts
|
||||||
|
const csv = await Csv.createCsvFromString('name,note\n"Ada","uses commas, safely"', {
|
||||||
|
headers: true,
|
||||||
|
unquote: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rows = await csv.exportAsObject();
|
||||||
|
|
||||||
|
console.log(rows[0].note); // 'uses commas, safely'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating CSV Strings
|
||||||
|
|
||||||
|
Use `Csv.createCsvStringFromArray()` to serialize an array of objects. The method builds the header row from all keys found across all objects, preserving first-seen key order.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Csv } from '@push.rocks/smartcsv';
|
||||||
|
|
||||||
|
const csvText = await Csv.createCsvStringFromArray([
|
||||||
|
{ name: 'Ada', role: 'Mathematician' },
|
||||||
|
{ name: 'Grace', city: 'New York' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
console.log(csvText);
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
```csv
|
||||||
|
name,role,city
|
||||||
|
Ada,Mathematician,
|
||||||
|
Grace,,New York
|
||||||
|
```
|
||||||
|
|
||||||
|
Missing values are serialized as empty cells. Values are converted with `String(value ?? '')`.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### `Csv.createCsvFromString(csvString, options)`
|
||||||
|
|
||||||
|
Creates and initializes a `Csv` instance from a CSV string.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const csv = await Csv.createCsvFromString(csvString, { headers: true });
|
||||||
|
```
|
||||||
|
|
||||||
|
### `csv.exportAsObject()`
|
||||||
|
|
||||||
|
Serializes the parsed CSV data into an array of objects and stores it on `csv.data`.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const rows = await csv.exportAsObject();
|
||||||
|
```
|
||||||
|
|
||||||
|
### `Csv.createCsvStringFromArray(array)`
|
||||||
|
|
||||||
|
Creates a CSV string from an array of flat objects.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const csvText = await Csv.createCsvStringFromArray([
|
||||||
|
{ id: 1, name: 'Ada' },
|
||||||
|
{ id: 2, name: 'Grace' },
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Public Instance Properties
|
||||||
|
|
||||||
|
| Property | Type | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `csvString` | `string` | The normalized CSV string used internally by the parser. |
|
||||||
|
| `headers` | `string[]` | Parsed header names. |
|
||||||
|
| `keyFrame` | `',' \| ';'` | Detected separator. |
|
||||||
|
| `data` | `Record<string, string>[]` | Last exported object rows. |
|
||||||
|
| `options` | `ICsvConstructorOptions` | Effective parser options. |
|
||||||
|
|
||||||
|
## TypeScript Types
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export type TCsvCellValue = string | number | boolean | null | undefined;
|
||||||
|
export type TCsvObjectRow = Record<string, TCsvCellValue>;
|
||||||
|
export type TCsvParsedRow = Record<string, string>;
|
||||||
|
```
|
||||||
|
|
||||||
|
`TCsvObjectRow` is used when creating CSV strings from objects. `TCsvParsedRow` is used when parsing CSV text back into objects.
|
||||||
|
|
||||||
|
## Runtime Support
|
||||||
|
|
||||||
|
`@push.rocks/smartcsv` is an ESM package and ships TypeScript declarations. It is tested for Node.js and Chromium-based browser environments through `@git.zone/tstest`.
|
||||||
|
|
||||||
## License and Legal Information
|
## License and Legal Information
|
||||||
|
|
||||||
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
|
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the [LICENSE](./LICENSE) file.
|
||||||
|
|
||||||
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
### Trademarks
|
### Trademarks
|
||||||
|
|
||||||
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
|
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
|
||||||
|
|
||||||
|
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
|
||||||
|
|
||||||
### Company Information
|
### Company Information
|
||||||
|
|
||||||
Task Venture Capital GmbH
|
Task Venture Capital GmbH
|
||||||
Registered at District court Bremen HRB 35230 HB, Germany
|
Registered at District Court Bremen HRB 35230 HB, Germany
|
||||||
|
|
||||||
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
|
For any legal inquiries or further information, please contact us via email at hello@task.vc.
|
||||||
|
|
||||||
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
Header 1;Header 2;"Header 3"
|
|
||||||
"row1data1";"row1data2";"row1data3"
|
|
||||||
"row2data1";row2data2;"row2data3"
|
|
||||||
|
@@ -0,0 +1,26 @@
|
|||||||
|
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||||
|
import * as smartcsv from '../ts/index.js';
|
||||||
|
|
||||||
|
const fileString = [
|
||||||
|
'Header 1;Header 2;"Header 3"',
|
||||||
|
'"row1data1";"row1data2";"row1data3"',
|
||||||
|
'"row2data1";row2data2;"row2data3"',
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
tap.test('should create a valid csv', async () => {
|
||||||
|
const testCsv = await smartcsv.Csv.createCsvFromString(fileString, { headers: true, unquote: true });
|
||||||
|
const result = await testCsv.exportAsObject();
|
||||||
|
expect(result[0]['Header 1']).toEqual('row1data1');
|
||||||
|
expect(result[0]['Header 3']).toEqual('row1data3');
|
||||||
|
expect(result[1]['Header 2']).toEqual('row2data2');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should create a valid csv string', async () => {
|
||||||
|
const createdCsvString = await smartcsv.Csv.createCsvStringFromArray([
|
||||||
|
{ wow: 'hi', wow2: 'there' },
|
||||||
|
{ wow: 'really', wow3: 'yes' },
|
||||||
|
]);
|
||||||
|
expect(createdCsvString).toEqual('wow,wow2,wow3\nhi,there,\nreally,,yes\n');
|
||||||
|
});
|
||||||
|
|
||||||
|
export default tap.start();
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
import { expect, tap } from '@pushrocks/tapbundle';
|
|
||||||
import * as smartcsv from '../ts/index.js';
|
|
||||||
|
|
||||||
import * as smartfile from '@pushrocks/smartfile';
|
|
||||||
|
|
||||||
let fileString: string;
|
|
||||||
let testCsv: smartcsv.Csv;
|
|
||||||
|
|
||||||
tap.test('should read a file', async (tools) => {
|
|
||||||
fileString = smartfile.fs.toStringSync('./test/sample.csv');
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('should create a valid csv', async () => {
|
|
||||||
testCsv = await smartcsv.Csv.createCsvFromString(fileString, { headers: true, unquote: true });
|
|
||||||
const result = await testCsv.exportAsObject();
|
|
||||||
console.log(result);
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.test('should create a valid csv string', async () => {
|
|
||||||
const createdCsvString = await smartcsv.Csv.createCsvStringFromArray([
|
|
||||||
{ wow: 'hi', wow2: 'there' },
|
|
||||||
{ wow: 'really', wow3: 'yes' },
|
|
||||||
]);
|
|
||||||
console.log(createdCsvString);
|
|
||||||
});
|
|
||||||
|
|
||||||
tap.start();
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
/**
|
/**
|
||||||
* autocreated commitinfo by @pushrocks/commitinfo
|
* autocreated commitinfo by @push.rocks/commitinfo
|
||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@pushrocks/smartcsv',
|
name: '@push.rocks/smartcsv',
|
||||||
version: '2.0.2',
|
version: '2.1.0',
|
||||||
description: 'handle csv data | gitzone standard compliant'
|
description: 'A module for handling CSV data compliant with Gitzone standard.'
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-13
@@ -1,5 +1,9 @@
|
|||||||
import * as plugins from './smartcsv.plugins.js';
|
import * as plugins from './smartcsv.plugins.js';
|
||||||
|
|
||||||
|
export type TCsvCellValue = string | number | boolean | null | undefined;
|
||||||
|
export type TCsvObjectRow = Record<string, TCsvCellValue>;
|
||||||
|
export type TCsvParsedRow = Record<string, string>;
|
||||||
|
|
||||||
export interface ICsvConstructorOptions {
|
export interface ICsvConstructorOptions {
|
||||||
headers: boolean;
|
headers: boolean;
|
||||||
unquote?: boolean;
|
unquote?: boolean;
|
||||||
@@ -24,7 +28,7 @@ export class Csv {
|
|||||||
return csvInstance;
|
return csvInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async createCsvStringFromArray(arrayArg: any[]): Promise<string> {
|
public static async createCsvStringFromArray(arrayArg: TCsvObjectRow[]): Promise<string> {
|
||||||
const foundKeys: string[] = [];
|
const foundKeys: string[] = [];
|
||||||
|
|
||||||
// lets deal with the keys
|
// lets deal with the keys
|
||||||
@@ -39,7 +43,7 @@ export class Csv {
|
|||||||
for (const objectArg of arrayArg) {
|
for (const objectArg of arrayArg) {
|
||||||
const dataRowArray: string[] = [];
|
const dataRowArray: string[] = [];
|
||||||
for (const key of foundKeys) {
|
for (const key of foundKeys) {
|
||||||
dataRowArray.push(objectArg[key]);
|
dataRowArray.push(String(objectArg[key] ?? ''));
|
||||||
}
|
}
|
||||||
dataRows.push(dataRowArray.join(','));
|
dataRows.push(dataRowArray.join(','));
|
||||||
}
|
}
|
||||||
@@ -53,9 +57,9 @@ export class Csv {
|
|||||||
|
|
||||||
// INSTANCE
|
// INSTANCE
|
||||||
public csvString: string;
|
public csvString: string;
|
||||||
public headers: string[];
|
public headers: string[] = [];
|
||||||
public keyFrame: string = null;
|
public keyFrame: ',' | ';' = ',';
|
||||||
public data: any[];
|
public data: TCsvParsedRow[] = [];
|
||||||
|
|
||||||
private base64RecognitionPrefix = '####12345####';
|
private base64RecognitionPrefix = '####12345####';
|
||||||
|
|
||||||
@@ -118,9 +122,9 @@ export class Csv {
|
|||||||
/**
|
/**
|
||||||
* serializes the csv string
|
* serializes the csv string
|
||||||
*/
|
*/
|
||||||
private serializeCsvString() {
|
private serializeCsvString(): string[][] {
|
||||||
const rowArray = this.getRows();
|
const rowArray = this.getRows();
|
||||||
const resultArray = [];
|
const resultArray: string[][] = [];
|
||||||
if (this.options.headers) {
|
if (this.options.headers) {
|
||||||
this.getHeaders();
|
this.getHeaders();
|
||||||
rowArray.shift();
|
rowArray.shift();
|
||||||
@@ -142,7 +146,7 @@ export class Csv {
|
|||||||
return rowsArray;
|
return rowsArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getHeaders() {
|
private getHeaders(): string[] {
|
||||||
const rowArray = this.getRows();
|
const rowArray = this.getRows();
|
||||||
if (this.options.headers) {
|
if (this.options.headers) {
|
||||||
let headerRow = rowArray[0];
|
let headerRow = rowArray[0];
|
||||||
@@ -160,7 +164,7 @@ export class Csv {
|
|||||||
this.headers = unquotedHeaders;
|
this.headers = unquotedHeaders;
|
||||||
}
|
}
|
||||||
if (this.options.trimSpace) {
|
if (this.options.trimSpace) {
|
||||||
const trimmedHeaders = [];
|
const trimmedHeaders: string[] = [];
|
||||||
for (const header of this.headers) {
|
for (const header of this.headers) {
|
||||||
trimmedHeaders.push(header.trim());
|
trimmedHeaders.push(header.trim());
|
||||||
}
|
}
|
||||||
@@ -170,9 +174,9 @@ export class Csv {
|
|||||||
return this.headers;
|
return this.headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
private createDataObject(dataArray: string[]) {
|
private createDataObject(dataArray: string[]): TCsvParsedRow {
|
||||||
const neededIterations = dataArray.length;
|
const neededIterations = dataArray.length;
|
||||||
let resultJson: any = {};
|
const resultJson: TCsvParsedRow = {};
|
||||||
for (let i = 0; i < neededIterations; i++) {
|
for (let i = 0; i < neededIterations; i++) {
|
||||||
let value = dataArray[i];
|
let value = dataArray[i];
|
||||||
if (this.options.unquote && value.startsWith(this.base64RecognitionPrefix)) {
|
if (this.options.unquote && value.startsWith(this.base64RecognitionPrefix)) {
|
||||||
@@ -190,9 +194,9 @@ export class Csv {
|
|||||||
return resultJson;
|
return resultJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async exportAsObject(): Promise<any> {
|
public async exportAsObject(): Promise<TCsvParsedRow[]> {
|
||||||
const serializedData = this.serializeCsvString();
|
const serializedData = this.serializeCsvString();
|
||||||
const dataObjects = [];
|
const dataObjects: TCsvParsedRow[] = [];
|
||||||
for (const dataArray of serializedData) {
|
for (const dataArray of serializedData) {
|
||||||
dataObjects.push(this.createDataObject(dataArray));
|
dataObjects.push(this.createDataObject(dataArray));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import * as smartpromise from '@pushrocks/smartpromise';
|
import * as smartstring from '@push.rocks/smartstring';
|
||||||
import * as smartstring from '@pushrocks/smartstring';
|
|
||||||
|
|
||||||
export { smartpromise, smartstring };
|
export { smartstring };
|
||||||
|
|||||||
+3
-1
@@ -5,8 +5,10 @@
|
|||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
|
"noImplicitAny": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"verbatimModuleSyntax": true
|
"verbatimModuleSyntax": true,
|
||||||
|
"types": ["node"]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"dist_*/**/*.d.ts"
|
"dist_*/**/*.d.ts"
|
||||||
|
|||||||
Reference in New Issue
Block a user