@blamejs/core 0.8.43 → 0.8.49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +92 -0
- package/README.md +10 -10
- package/index.js +52 -0
- package/lib/a2a.js +159 -34
- package/lib/acme.js +762 -0
- package/lib/ai-pref.js +166 -43
- package/lib/api-key.js +108 -47
- package/lib/api-snapshot.js +157 -40
- package/lib/app-shutdown.js +113 -77
- package/lib/archive.js +337 -40
- package/lib/arg-parser.js +697 -0
- package/lib/asyncapi.js +99 -55
- package/lib/atomic-file.js +465 -104
- package/lib/audit-chain.js +123 -34
- package/lib/audit-daily-review.js +389 -0
- package/lib/audit-sign.js +302 -56
- package/lib/audit-tools.js +412 -63
- package/lib/audit.js +656 -35
- package/lib/auth/jwt-external.js +17 -0
- package/lib/auth/oauth.js +7 -0
- package/lib/auth-bot-challenge.js +505 -0
- package/lib/auth-header.js +92 -25
- package/lib/backup/bundle.js +26 -0
- package/lib/backup/index.js +512 -89
- package/lib/backup/manifest.js +168 -7
- package/lib/break-glass.js +415 -39
- package/lib/budr.js +103 -30
- package/lib/bundler.js +86 -66
- package/lib/cache.js +192 -72
- package/lib/chain-writer.js +65 -40
- package/lib/circuit-breaker.js +56 -33
- package/lib/cli-helpers.js +106 -75
- package/lib/cli.js +6 -30
- package/lib/cloud-events.js +99 -32
- package/lib/cluster-storage.js +162 -37
- package/lib/cluster.js +340 -49
- package/lib/codepoint-class.js +66 -0
- package/lib/compliance.js +424 -24
- package/lib/config-drift.js +111 -46
- package/lib/config.js +94 -40
- package/lib/consent.js +165 -18
- package/lib/constants.js +1 -0
- package/lib/content-credentials.js +153 -48
- package/lib/cookies.js +154 -62
- package/lib/credential-hash.js +133 -61
- package/lib/crypto-field.js +702 -18
- package/lib/crypto-hpke.js +256 -0
- package/lib/crypto.js +744 -22
- package/lib/csv.js +178 -35
- package/lib/daemon.js +456 -0
- package/lib/dark-patterns.js +186 -55
- package/lib/db-query.js +79 -2
- package/lib/db.js +1431 -60
- package/lib/ddl-change-control.js +523 -0
- package/lib/deprecate.js +195 -40
- package/lib/dev.js +82 -39
- package/lib/dora.js +67 -48
- package/lib/dr-runbook.js +368 -0
- package/lib/dsr.js +142 -11
- package/lib/dual-control.js +91 -56
- package/lib/events.js +120 -41
- package/lib/external-db-migrate.js +192 -2
- package/lib/external-db.js +795 -50
- package/lib/fapi2.js +122 -1
- package/lib/fda-21cfr11.js +395 -0
- package/lib/fdx.js +132 -2
- package/lib/file-type.js +87 -0
- package/lib/file-upload.js +93 -0
- package/lib/flag.js +82 -20
- package/lib/forms.js +132 -29
- package/lib/framework-error.js +169 -0
- package/lib/framework-schema.js +163 -35
- package/lib/gate-contract.js +849 -175
- package/lib/graphql-federation.js +68 -7
- package/lib/guard-all.js +172 -55
- package/lib/guard-archive.js +286 -124
- package/lib/guard-auth.js +194 -21
- package/lib/guard-cidr.js +190 -28
- package/lib/guard-csv.js +397 -51
- package/lib/guard-domain.js +213 -91
- package/lib/guard-email.js +236 -29
- package/lib/guard-filename.js +307 -75
- package/lib/guard-graphql.js +263 -30
- package/lib/guard-html.js +310 -116
- package/lib/guard-image.js +243 -30
- package/lib/guard-json.js +260 -54
- package/lib/guard-jsonpath.js +235 -23
- package/lib/guard-jwt.js +284 -30
- package/lib/guard-markdown.js +204 -22
- package/lib/guard-mime.js +190 -26
- package/lib/guard-oauth.js +277 -28
- package/lib/guard-pdf.js +251 -27
- package/lib/guard-regex.js +226 -18
- package/lib/guard-shell.js +229 -26
- package/lib/guard-svg.js +177 -10
- package/lib/guard-template.js +232 -21
- package/lib/guard-time.js +195 -29
- package/lib/guard-uuid.js +189 -30
- package/lib/guard-xml.js +259 -36
- package/lib/guard-yaml.js +241 -44
- package/lib/honeytoken.js +63 -27
- package/lib/html-balance.js +83 -0
- package/lib/http-client.js +486 -59
- package/lib/http-message-signature.js +582 -0
- package/lib/i18n.js +102 -49
- package/lib/iab-mspa.js +112 -32
- package/lib/iab-tcf.js +107 -2
- package/lib/inbox.js +90 -52
- package/lib/keychain.js +865 -0
- package/lib/legal-hold.js +374 -0
- package/lib/local-db-thin.js +320 -0
- package/lib/log-stream.js +281 -51
- package/lib/log.js +184 -86
- package/lib/mail-bounce.js +107 -62
- package/lib/mail.js +295 -58
- package/lib/mcp.js +108 -27
- package/lib/metrics.js +98 -89
- package/lib/middleware/age-gate.js +36 -0
- package/lib/middleware/ai-act-disclosure.js +37 -0
- package/lib/middleware/api-encrypt.js +45 -0
- package/lib/middleware/assetlinks.js +40 -0
- package/lib/middleware/asyncapi-serve.js +35 -0
- package/lib/middleware/attach-user.js +40 -0
- package/lib/middleware/bearer-auth.js +40 -0
- package/lib/middleware/body-parser.js +230 -0
- package/lib/middleware/bot-disclose.js +34 -0
- package/lib/middleware/bot-guard.js +39 -0
- package/lib/middleware/compression.js +37 -0
- package/lib/middleware/cookies.js +32 -0
- package/lib/middleware/cors.js +40 -0
- package/lib/middleware/csp-nonce.js +40 -0
- package/lib/middleware/csp-report.js +34 -0
- package/lib/middleware/csrf-protect.js +43 -0
- package/lib/middleware/daily-byte-quota.js +53 -85
- package/lib/middleware/db-role-for.js +40 -0
- package/lib/middleware/dpop.js +40 -0
- package/lib/middleware/error-handler.js +37 -14
- package/lib/middleware/fetch-metadata.js +39 -0
- package/lib/middleware/flag-context.js +34 -0
- package/lib/middleware/gpc.js +33 -0
- package/lib/middleware/headers.js +35 -0
- package/lib/middleware/health.js +46 -0
- package/lib/middleware/host-allowlist.js +30 -0
- package/lib/middleware/network-allowlist.js +38 -0
- package/lib/middleware/openapi-serve.js +34 -0
- package/lib/middleware/rate-limit.js +160 -18
- package/lib/middleware/request-id.js +36 -18
- package/lib/middleware/request-log.js +37 -0
- package/lib/middleware/require-aal.js +29 -0
- package/lib/middleware/require-auth.js +32 -0
- package/lib/middleware/require-bound-key.js +41 -0
- package/lib/middleware/require-content-type.js +32 -0
- package/lib/middleware/require-methods.js +27 -0
- package/lib/middleware/require-mtls.js +33 -0
- package/lib/middleware/require-step-up.js +37 -0
- package/lib/middleware/security-headers.js +44 -0
- package/lib/middleware/security-txt.js +38 -0
- package/lib/middleware/span-http-server.js +37 -0
- package/lib/middleware/sse.js +36 -0
- package/lib/middleware/trace-log-correlation.js +33 -0
- package/lib/middleware/trace-propagate.js +32 -0
- package/lib/middleware/tus-upload.js +90 -0
- package/lib/middleware/web-app-manifest.js +53 -0
- package/lib/mtls-ca.js +100 -70
- package/lib/network-byte-quota.js +308 -0
- package/lib/network-heartbeat.js +135 -0
- package/lib/network-tls.js +534 -4
- package/lib/network.js +103 -0
- package/lib/notify.js +114 -43
- package/lib/ntp-check.js +192 -51
- package/lib/observability.js +145 -47
- package/lib/openapi.js +90 -44
- package/lib/outbox.js +99 -1
- package/lib/pagination.js +168 -86
- package/lib/parsers/index.js +16 -5
- package/lib/permissions.js +93 -40
- package/lib/pqc-agent.js +84 -8
- package/lib/pqc-software.js +94 -60
- package/lib/process-spawn.js +95 -21
- package/lib/pubsub.js +96 -66
- package/lib/queue.js +375 -54
- package/lib/redact.js +793 -21
- package/lib/render.js +139 -47
- package/lib/request-helpers.js +485 -121
- package/lib/restore-bundle.js +142 -39
- package/lib/restore-rollback.js +136 -45
- package/lib/retention.js +178 -50
- package/lib/retry.js +116 -33
- package/lib/router.js +475 -23
- package/lib/safe-async.js +543 -94
- package/lib/safe-buffer.js +337 -41
- package/lib/safe-json.js +467 -62
- package/lib/safe-jsonpath.js +285 -0
- package/lib/safe-schema.js +631 -87
- package/lib/safe-sql.js +221 -59
- package/lib/safe-url.js +278 -46
- package/lib/sandbox-worker.js +135 -0
- package/lib/sandbox.js +358 -0
- package/lib/scheduler.js +135 -70
- package/lib/self-update.js +647 -0
- package/lib/session-device-binding.js +431 -0
- package/lib/session.js +259 -49
- package/lib/slug.js +138 -26
- package/lib/ssrf-guard.js +316 -56
- package/lib/storage.js +433 -70
- package/lib/subject.js +405 -23
- package/lib/template.js +148 -8
- package/lib/tenant-quota.js +545 -0
- package/lib/testing.js +440 -53
- package/lib/time.js +291 -23
- package/lib/tls-exporter.js +239 -0
- package/lib/tracing.js +90 -74
- package/lib/uuid.js +97 -22
- package/lib/vault/index.js +284 -22
- package/lib/vault/seal-pem-file.js +66 -0
- package/lib/watcher.js +368 -0
- package/lib/webhook.js +196 -63
- package/lib/websocket.js +393 -68
- package/lib/wiki-concepts.js +338 -0
- package/lib/worker-pool.js +464 -0
- package/package.json +3 -3
- package/sbom.cyclonedx.json +7 -7
package/lib/csv.js
CHANGED
|
@@ -1,54 +1,90 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @module b.csv
|
|
4
|
+
* @featured true
|
|
5
|
+
* @nav Tools
|
|
6
|
+
* @title CSV
|
|
4
7
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* // [ { name: "alice", age: "30" }, ... ]
|
|
8
|
+
* @intro
|
|
9
|
+
* RFC 4180 parser + serializer with operator-friendly defaults.
|
|
8
10
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
+
* `b.csv.parse` accepts a string, Buffer, or Uint8Array and returns
|
|
12
|
+
* either an array of row objects (header mode, default) or an array
|
|
13
|
+
* of arrays (when `header: false`). Strips a leading UTF-8 BOM,
|
|
14
|
+
* handles CRLF / LF / CR line endings, and supports doubled-quote
|
|
15
|
+
* escapes inside quoted fields.
|
|
11
16
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
17
|
+
* `b.csv.stringify` accepts an array of objects or arrays and emits
|
|
18
|
+
* RFC 4180 output. Cells are quoted only when they contain the
|
|
19
|
+
* delimiter, the quote char, CR, or LF — unless `alwaysQuote: true`
|
|
20
|
+
* forces full quoting.
|
|
14
21
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* quote: '"'
|
|
20
|
-
* trim: false cell whitespace preserved
|
|
21
|
-
* maxBytes: 16 MiB
|
|
22
|
-
* maxRows: 1,000,000
|
|
23
|
-
* maxFieldBytes: 1 MiB
|
|
24
|
-
* onBadRow: "throw" "skip" tolerates short/long rows
|
|
22
|
+
* Anti-DoS bounds are on by default: `maxBytes` (16 MiB),
|
|
23
|
+
* `maxRows` (1,000,000), and `maxFieldBytes` (1 MiB). Each cap is
|
|
24
|
+
* validated as a positive finite integer at call time — passing
|
|
25
|
+
* `Infinity` throws, never a silent bypass.
|
|
25
26
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
27
|
+
* SCOPE: this module is for trusted-source-only emission. It performs
|
|
28
|
+
* RFC 4180 quote/delimiter escaping but does NOT defend against the
|
|
29
|
+
* broader CSV-injection threat catalog (Excel/Sheets formula
|
|
30
|
+
* triggers, Unicode bidi overrides, dangerous-function denylist,
|
|
31
|
+
* homoglyphs, control-byte injection, BOM mid-stream, dialect
|
|
32
|
+
* ambiguity, CSV-bombs). Any path that emits or accepts user-supplied
|
|
33
|
+
* cells MUST route through `b.guardCsv` — its serialize / validate /
|
|
34
|
+
* sanitize / gate surface handles every documented threat with a
|
|
35
|
+
* single profile choice (strict / balanced / permissive /
|
|
36
|
+
* email-attachment) or compliance posture (hipaa / pci-dss / gdpr /
|
|
37
|
+
* soc2).
|
|
32
38
|
*
|
|
33
|
-
*
|
|
34
|
-
* 4180 quote/delimiter escaping but does NOT defend against the broader
|
|
35
|
-
* CSV-injection threat catalog (Excel/Sheets formula triggers, Unicode
|
|
36
|
-
* bidi overrides, dangerous-function denylist, homoglyphs, control-byte
|
|
37
|
-
* injection, BOM mid-stream, dialect ambiguity, CSV-bombs). Any path
|
|
38
|
-
* that emits or accepts user-supplied cells MUST route through
|
|
39
|
-
* `b.guardCsv` — its `serialize` / `validate` / `sanitize` / `gate`
|
|
40
|
-
* surface handles every documented threat with a single profile choice
|
|
41
|
-
* (strict / balanced / permissive / email-attachment) or compliance
|
|
42
|
-
* posture (hipaa / pci-dss / gdpr / soc2).
|
|
39
|
+
* Throws `CsvError` (FrameworkError, permanent) on shape violations.
|
|
43
40
|
*
|
|
44
|
-
*
|
|
41
|
+
* @card
|
|
42
|
+
* RFC 4180 parser + serializer with operator-friendly defaults.
|
|
45
43
|
*/
|
|
46
44
|
var C = require("./constants");
|
|
47
45
|
var numericBounds = require("./numeric-bounds");
|
|
48
46
|
var { defineClass } = require("./framework-error");
|
|
49
47
|
|
|
48
|
+
/**
|
|
49
|
+
* @primitive b.csv.CsvError
|
|
50
|
+
* @signature b.csv.CsvError
|
|
51
|
+
* @since 0.4.0
|
|
52
|
+
* @related b.csv.parse, b.csv.stringify
|
|
53
|
+
*
|
|
54
|
+
* FrameworkError subclass thrown by `b.csv.parse` and
|
|
55
|
+
* `b.csv.stringify` on shape violations: bad delimiter / quote,
|
|
56
|
+
* unterminated quoted field, oversized input, oversized field,
|
|
57
|
+
* row-length mismatch, or unsupported `eol` / `onBadRow` value.
|
|
58
|
+
* `alwaysPermanent` — never retried by `b.retry`. Operators catch
|
|
59
|
+
* it to distinguish CSV-shape problems from upstream IO errors.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* try {
|
|
63
|
+
* b.csv.parse('name,age\n"unterminated', { header: true });
|
|
64
|
+
* } catch (e) {
|
|
65
|
+
* e instanceof b.csv.CsvError; // → true
|
|
66
|
+
* e.code; // → "csv/unterminated-quote"
|
|
67
|
+
* }
|
|
68
|
+
*/
|
|
50
69
|
var CsvError = defineClass("CsvError", { alwaysPermanent: true });
|
|
51
70
|
|
|
71
|
+
/**
|
|
72
|
+
* @primitive b.csv.DEFAULTS_PARSE
|
|
73
|
+
* @signature b.csv.DEFAULTS_PARSE
|
|
74
|
+
* @since 0.4.0
|
|
75
|
+
* @related b.csv.parse, b.csv.DEFAULTS_STRINGIFY
|
|
76
|
+
*
|
|
77
|
+
* Frozen-by-convention defaults applied to `b.csv.parse(input, opts)`
|
|
78
|
+
* before the call's own `opts` overlay. Exposed so operators can
|
|
79
|
+
* introspect the active limits (`maxBytes`, `maxRows`,
|
|
80
|
+
* `maxFieldBytes`) without re-deriving them from documentation.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* b.csv.DEFAULTS_PARSE.maxBytes; // → 16777216 (16 MiB)
|
|
84
|
+
* b.csv.DEFAULTS_PARSE.maxRows; // → 1000000
|
|
85
|
+
* b.csv.DEFAULTS_PARSE.maxFieldBytes; // → 1048576 (1 MiB)
|
|
86
|
+
* b.csv.DEFAULTS_PARSE.delimiter; // → ","
|
|
87
|
+
*/
|
|
52
88
|
var DEFAULTS_PARSE = {
|
|
53
89
|
header: true,
|
|
54
90
|
delimiter: ",",
|
|
@@ -60,6 +96,23 @@ var DEFAULTS_PARSE = {
|
|
|
60
96
|
onBadRow: "throw",
|
|
61
97
|
};
|
|
62
98
|
|
|
99
|
+
/**
|
|
100
|
+
* @primitive b.csv.DEFAULTS_STRINGIFY
|
|
101
|
+
* @signature b.csv.DEFAULTS_STRINGIFY
|
|
102
|
+
* @since 0.4.0
|
|
103
|
+
* @related b.csv.stringify, b.csv.DEFAULTS_PARSE
|
|
104
|
+
*
|
|
105
|
+
* Frozen-by-convention defaults applied to `b.csv.stringify(rows, opts)`
|
|
106
|
+
* before the call's own `opts` overlay. Exposed so operators can
|
|
107
|
+
* introspect the active emission policy (`eol`, `delimiter`,
|
|
108
|
+
* `alwaysQuote`) without re-deriving it from documentation.
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* b.csv.DEFAULTS_STRINGIFY.header; // → true
|
|
112
|
+
* b.csv.DEFAULTS_STRINGIFY.delimiter; // → ","
|
|
113
|
+
* b.csv.DEFAULTS_STRINGIFY.eol; // → "\r\n"
|
|
114
|
+
* b.csv.DEFAULTS_STRINGIFY.alwaysQuote; // → false
|
|
115
|
+
*/
|
|
63
116
|
var DEFAULTS_STRINGIFY = {
|
|
64
117
|
header: true,
|
|
65
118
|
delimiter: ",",
|
|
@@ -82,6 +135,49 @@ function _validateDelim(name, value) {
|
|
|
82
135
|
|
|
83
136
|
// ---- parse ----
|
|
84
137
|
|
|
138
|
+
/**
|
|
139
|
+
* @primitive b.csv.parse
|
|
140
|
+
* @signature b.csv.parse(input, opts?)
|
|
141
|
+
* @since 0.4.0
|
|
142
|
+
* @related b.csv.stringify, b.csv.DEFAULTS_PARSE
|
|
143
|
+
*
|
|
144
|
+
* Parse RFC 4180 CSV text into rows. By default the first row is
|
|
145
|
+
* treated as a header and each subsequent row is returned as an
|
|
146
|
+
* object keyed by header name; pass `header: false` to receive
|
|
147
|
+
* an array of arrays instead. Accepts a string, Buffer, or
|
|
148
|
+
* Uint8Array; a leading UTF-8 BOM is stripped. CR, LF, and CRLF
|
|
149
|
+
* are all accepted as row terminators. Doubled-quote sequences
|
|
150
|
+
* inside a quoted field decode to a literal quote character.
|
|
151
|
+
*
|
|
152
|
+
* Anti-DoS caps (`maxBytes`, `maxRows`, `maxFieldBytes`) are
|
|
153
|
+
* enforced as positive finite integers. Passing `Infinity` or
|
|
154
|
+
* `NaN` throws `CsvError` rather than silently disabling the cap.
|
|
155
|
+
*
|
|
156
|
+
* @opts
|
|
157
|
+
* header: boolean, // first row is column names (default true)
|
|
158
|
+
* delimiter: string, // single byte, default ","
|
|
159
|
+
* quote: string, // single byte, default '"'
|
|
160
|
+
* trim: boolean, // strip leading/trailing whitespace per cell
|
|
161
|
+
* maxBytes: number, // input cap, default 16 MiB
|
|
162
|
+
* maxRows: number, // row-count cap, default 1,000,000
|
|
163
|
+
* maxFieldBytes: number, // per-cell cap, default 1 MiB
|
|
164
|
+
* onBadRow: string, // "throw" (default) or "skip"
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* var rows = b.csv.parse("name,age\nalice,30\nbob,25");
|
|
168
|
+
* // → [ { name: "alice", age: "30" }, { name: "bob", age: "25" } ]
|
|
169
|
+
*
|
|
170
|
+
* var arrays = b.csv.parse("a,b\n1,2", { header: false });
|
|
171
|
+
* // → [ [ "a", "b" ], [ "1", "2" ] ]
|
|
172
|
+
*
|
|
173
|
+
* // Doubled-quote escape inside a quoted field decodes to one quote.
|
|
174
|
+
* var quoted = b.csv.parse('msg\n"she said ""hi"""', { header: true });
|
|
175
|
+
* // → [ { msg: 'she said "hi"' } ]
|
|
176
|
+
*
|
|
177
|
+
* // Tab-separated values via the delimiter opt.
|
|
178
|
+
* var tsv = b.csv.parse("a\tb\n1\t2", { delimiter: "\t" });
|
|
179
|
+
* // → [ { a: "1", b: "2" } ]
|
|
180
|
+
*/
|
|
85
181
|
function parse(input, opts) {
|
|
86
182
|
opts = Object.assign({}, DEFAULTS_PARSE, opts || {});
|
|
87
183
|
// maxBytes / maxRows / maxFieldBytes via shared lib/numeric-bounds —
|
|
@@ -204,6 +300,53 @@ function parse(input, opts) {
|
|
|
204
300
|
|
|
205
301
|
// ---- stringify ----
|
|
206
302
|
|
|
303
|
+
/**
|
|
304
|
+
* @primitive b.csv.stringify
|
|
305
|
+
* @signature b.csv.stringify(rows, opts?)
|
|
306
|
+
* @since 0.4.0
|
|
307
|
+
* @related b.csv.parse, b.csv.DEFAULTS_STRINGIFY
|
|
308
|
+
*
|
|
309
|
+
* Serialize an array of rows to RFC 4180 CSV text. Rows may be
|
|
310
|
+
* arrays (positional) or plain objects (keyed by header). When the
|
|
311
|
+
* first row is an object, header columns default to that row's
|
|
312
|
+
* `Object.keys`; pass `opts.columns` to force an explicit column
|
|
313
|
+
* order or to surface keys missing from the first row. Cells are
|
|
314
|
+
* quoted only when they contain the delimiter, the quote char,
|
|
315
|
+
* CR, or LF — unless `alwaysQuote: true` forces full quoting.
|
|
316
|
+
* `null` and `undefined` cells emit as empty strings; everything
|
|
317
|
+
* else is coerced via `String()`.
|
|
318
|
+
*
|
|
319
|
+
* The default end-of-line is CRLF per RFC 4180; pass `eol: "\n"`
|
|
320
|
+
* for plain LF output.
|
|
321
|
+
*
|
|
322
|
+
* @opts
|
|
323
|
+
* header: boolean, // emit a header row (default true)
|
|
324
|
+
* delimiter: string, // single byte, default ","
|
|
325
|
+
* quote: string, // single byte, default '"'
|
|
326
|
+
* eol: string, // "\r\n" (default) or "\n"
|
|
327
|
+
* alwaysQuote: boolean, // quote every cell unconditionally
|
|
328
|
+
* columns: Array<string>, // explicit column order / subset
|
|
329
|
+
*
|
|
330
|
+
* @example
|
|
331
|
+
* var out = b.csv.stringify([
|
|
332
|
+
* { name: "alice", age: 30 },
|
|
333
|
+
* { name: "bob", age: 25 },
|
|
334
|
+
* ]);
|
|
335
|
+
* // → "name,age\r\nalice,30\r\nbob,25"
|
|
336
|
+
*
|
|
337
|
+
* // Cells containing the delimiter are quoted; embedded quotes double.
|
|
338
|
+
* var quoted = b.csv.stringify([
|
|
339
|
+
* { msg: 'she said "hi", then left' },
|
|
340
|
+
* ], { eol: "\n" });
|
|
341
|
+
* // → 'msg\n"she said ""hi"", then left"'
|
|
342
|
+
*
|
|
343
|
+
* // Array-of-arrays input with an explicit column header.
|
|
344
|
+
* var cols = b.csv.stringify(
|
|
345
|
+
* [ [ "1", "2" ], [ "3", "4" ] ],
|
|
346
|
+
* { columns: [ "a", "b" ], eol: "\n" }
|
|
347
|
+
* );
|
|
348
|
+
* // → "a,b\n1,2\n3,4"
|
|
349
|
+
*/
|
|
207
350
|
function stringify(rows, opts) {
|
|
208
351
|
opts = Object.assign({}, DEFAULTS_STRINGIFY, opts || {});
|
|
209
352
|
if (!Array.isArray(rows)) {
|