properties-file 5.0.0 → 5.0.1

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/README.md CHANGED
@@ -1,253 +1,253 @@
1
- # properties-file
2
-
3
- [![License](https://img.shields.io/npm/l/make-coverage-badge.svg?color=brightgreen)](https://opensource.org/licenses/MIT)
4
- [![Download Stats](https://img.shields.io/npm/dw/properties-file.svg?color=brightgreen)](https://www.npmjs.com/package/properties-file)
5
- ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)
6
- ![Package Size](https://img.shields.io/badge/min%2Bgzip-1.1%20kB-brightgreen)
7
- ![Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
8
-
9
- `.properties` file parser, editor, formatter and bundler integrations.
10
-
11
- ## Installation
12
-
13
- > Doing a major version update? Check our [migration guides](./docs/migration/README.md).
14
-
15
- Add the package as a dependency:
16
-
17
- ```
18
- npm install properties-file
19
- ```
20
-
21
- ## What's in it for me?
22
-
23
- - A modern library written entirely in TypeScript that exactly reproduces the [Properties Java implementation](/assets/java-implementation.md).
24
- - Works for both Node.js applications and browsers that support at least [ES5](https://www.w3schools.com/js/js_es5.asp).
25
- - Flexible, tree-shakable APIs — import only what you need, and your bundler will exclude the rest:
26
- - `getProperties` converts `.properties` content to a key-value pair object.
27
- - `Properties` provides lossless parsing with a full data model — every element (properties, comments, blank lines, whitespace, duplicate keys) is preserved and can be round-tripped exactly or normalized via `format()` options.
28
- - `PropertiesEditor` enables insertion, edition, and removal of entries while preserving formatting.
29
- - `escapeKey` and `escapeValue` convert any content to `.properties` compatible format.
30
- - Bundler integrations for Webpack, Rollup/Vite, esbuild, and Bun to import `.properties` files directly. See [BUNDLER.md](./docs/BUNDLER.md).
31
- - **Tiny with 0 dependencies** — `getProperties` is only 1.1 kB min+gzip.
32
- - **Runs everywhere** — compiled to ES5, works in any browser and on Node.js all the way back to v0.10 (2013). [Verified via Docker](./tests/node-compat/).
33
- - **100% test coverage** based on the output from a Java implementation.
34
- - Active maintenance (many popular `.properties` packages have been inactive for years). See our [detailed comparison](./docs/COMPARISON.md) with other packages.
35
-
36
- ## Usage
37
-
38
- We have put a lot of effort into incorporating [TSDoc](https://tsdoc.org/) into all our APIs. If you are unsure about how to use certain APIs provided in our examples, please check directly in your IDE.
39
-
40
- ### `getProperties` (converting `.properties` to an object)
41
-
42
- The most common use case for `.properties` files is for Node.js applications that need to read the file's content into a simple key-value pair object. Here is how this can be done with a single API call:
43
-
44
- ```ts
45
- import { readFileSync } from 'node:fs'
46
- import { getProperties } from 'properties-file'
47
-
48
- console.log(getProperties(readFileSync('hello-world.properties')))
49
- ```
50
-
51
- Output:
52
-
53
- ```js
54
- { hello: 'hello', world: 'world' }
55
- ```
56
-
57
- ### `Properties` (lossless parsing with full data model)
58
-
59
- The `Properties` class parses a `.properties` file into a lossless data model where every element — properties, comments, blank lines — is preserved in order. This is useful when you need to inspect, analyze, or transform `.properties` files while retaining their exact structure.
60
-
61
- ```ts
62
- import { readFileSync } from 'node:fs'
63
- import { PropertiesNodeType, Properties } from 'properties-file/parser'
64
-
65
- const properties = new Properties(readFileSync('example.properties'))
66
-
67
- // Access all nodes in file order (properties, comments, blank lines).
68
- for (const node of properties.nodes) {
69
- switch (node.type) {
70
- case PropertiesNodeType.PROPERTY:
71
- console.log(`${node.key} = ${node.value}`)
72
- break
73
- case PropertiesNodeType.COMMENT:
74
- console.log(`Comment: ${node.delimiter}${node.body}`)
75
- break
76
- case PropertiesNodeType.BLANK:
77
- console.log('(blank line)')
78
- break
79
- }
80
- }
81
-
82
- // Get a simple key-value object (last-wins for duplicate keys).
83
- console.log(properties.toObject())
84
-
85
- // Lossless round-trip: format() reproduces the exact original content.
86
- console.log(properties.format() === readFileSync('example.properties', 'utf8')) // true
87
- ```
88
-
89
- #### Finding key collisions
90
-
91
- ```ts
92
- import { Properties } from 'properties-file/parser'
93
-
94
- const properties = new Properties(
95
- 'hello = hello1\nworld = world1\nworld = world2\nhello = hello2\nworld = world3'
96
- )
97
-
98
- const collisions = properties.getKeyCollisions()
99
- collisions.forEach((collision) => {
100
- const lines = collision.nodes.map((node) => node.startingLineNumber)
101
- console.log(`Key '${collision.key}' appears on lines ${lines.join(', ')}`)
102
- })
103
-
104
- /**
105
- * Outputs:
106
- *
107
- * Key 'hello' appears on lines 1, 4
108
- * Key 'world' appears on lines 2, 3, 5
109
- */
110
- ```
111
-
112
- #### Normalizing output
113
-
114
- Passing options to `format()` produces a normalized version of the file with granular control over formatting:
115
-
116
- ```ts
117
- import { Properties } from 'properties-file/parser'
118
-
119
- const properties = new Properties('# comment\n\n key : value\n key : updated')
120
-
121
- console.log(
122
- properties.format({
123
- removeComments: true, // Strip all comments
124
- removeBlankLines: true, // Strip all blank lines
125
- removeLeadingWhitespace: true, // Strip indentation
126
- deduplicateKeys: true, // Keep only last occurrence
127
- separatorChar: '=', // Standardize separator
128
- separatorLeading: ' ', // Space before =
129
- separatorTrailing: ' ', // Space after =
130
- })
131
- )
132
-
133
- /**
134
- * Outputs:
135
- *
136
- * key = updated
137
- */
138
- ```
139
-
140
- ### `PropertiesEditor` (editing `.properties` content)
141
-
142
- The `PropertiesEditor` extends `Properties` with methods to insert, update, delete, and upsert entries while preserving formatting.
143
-
144
- ```ts
145
- import { PropertiesEditor } from 'properties-file/editor'
146
-
147
- const properties = new PropertiesEditor('hello = hello\n# This is a comment\nworld = world')
148
-
149
- properties.insertComment('This is a multiline\ncomment before `newKey3`')
150
- properties.insert('newKey3', 'This is my third key')
151
-
152
- properties.insert('newKey1', 'This is my first new key', {
153
- referenceKey: 'newKey3',
154
- position: 'before',
155
- comment: 'Below are the new keys being edited',
156
- commentDelimiter: '!',
157
- })
158
-
159
- properties.insert('newKey2', 'hello', {
160
- referenceKey: 'newKey1',
161
- position: 'after',
162
- escapeUnicode: true,
163
- })
164
-
165
- properties.delete('hello')
166
- properties.update('world', {
167
- newValue: 'new world',
168
- })
169
- console.log(properties.format())
170
-
171
- /**
172
- * Outputs:
173
- *
174
- * # This is a comment
175
- * world = new world
176
- * ! Below are the new keys being edited
177
- * newKey1 = This is my first new key
178
- * newKey2 = hello
179
- * # This is a multiline
180
- * # comment before `newKey3`
181
- * newKey3 = This is my third key
182
- */
183
- ```
184
-
185
- The editor also provides `upsert` (update or insert) and `deleteAll` (remove all occurrences of a duplicate key). Check your IDE for all available methods and options via TSDoc.
186
-
187
- ### Bundler Integrations
188
-
189
- If you would like to import `.properties` directly using `import`, this package provides integrations for all major bundlers: **Webpack/Rspack**, **Rollup/Vite/Rolldown**, **esbuild**, and **Bun**.
190
-
191
- See [BUNDLER.md](./docs/BUNDLER.md) for setup instructions and examples.
192
-
193
- By adding these configurations you should now be able to import directly `.properties` files just like this:
194
-
195
- ```ts
196
- import { properties as helloWorld } from './hello-world.properties'
197
-
198
- console.dir(helloWorld)
199
- ```
200
-
201
- Output:
202
-
203
- ```json
204
- { "hello": "world" }
205
- ```
206
-
207
- ## Why another `.properties` file package?
208
-
209
- There are over 20 similar packages available, but most are abandoned, incomplete, or not compliant with the Java specification. See our [detailed comparison](./docs/COMPARISON.md) for benchmarks, compliance tests, and a feature matrix against the top 5 packages. The short version:
210
-
211
- - **100% Java spec compliance** — the only package (alongside `properties-parser`) to pass all test cases.
212
- - **3–7x faster** than alternatives on a 10,000-entry file.
213
- - **Lossless data model** — no other package preserves comments, blank lines, whitespace, and duplicate keys for round-trip editing.
214
-
215
- Unfortunately, the `.properties` file specification is not well-documented. One reason for this is that it was originally used in Java to store configurations. Today, most applications handle this using JSON, YAML, or other modern formats because these formats are more flexible.
216
-
217
- ### So why `.properties` files?
218
-
219
- While many options exist today to handle configurations, `.properties` files remain one of the best options to store localizable strings (also known as messages). On the Java side, `PropertyResourceBundle` is how most implementations handle localization today. Because of its simplicity and maturity, `.properties` files remain one of the best options today when it comes to internationalization (i18n):
220
-
221
- | File format | Key/value based | Supports inline comments | Built for localization | Good linguistic tools support |
222
- | ------------- | ---------------- | ------------------------ | ---------------------- | ----------------------------- |
223
- | `.properties` | Yes | Yes | Yes (Resource Bundles) | Yes |
224
- | `JSON` | No (can do more) | No (requires JSON5) | No | Depends on the schema |
225
- | `YAML` | No (can do more) | Yes | No | Depends on the schema |
226
-
227
- Having good JavaScript/TypeScript support for `.properties` files offers more internationalization (i18n) options.
228
-
229
- ### How does this package work?
230
-
231
- Our goal is to offer parity with the Java implementation, which is the closest thing to a specification for `.properties` files. The package provides two parsing paths:
232
-
233
- 1. **`getProperties`** — a fast, functional parser optimized for the common case of converting `.properties` content to a key-value object. Uses `charCodeAt`-based scanning with zero-copy optimizations.
234
-
235
- 2. **`Properties`** — a lossless parser that produces an ordered array of typed nodes (`PropertyNode`, `CommentNode`, `BlankLineNode`). Every element in the file is preserved, enabling exact round-trip reconstruction via `format()` and flexible normalization by passing options to `format()`.
236
-
237
- Both parsers are fully compliant with the Java `Properties` specification and produce identical key-value output. Just like Java, if a Unicode-escaped character (`\u`) is malformed, an error will be thrown.
238
-
239
- ## Contributing
240
-
241
- See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for project principles, architecture, code style, and development commands.
242
-
243
- ## Additional references
244
-
245
- - Java [Test Sandbox](https://codehs.com/sandbox/id/java-main-FObePj)
246
- - Java's `Properties` class [documentation](https://docs.oracle.com/javase/9/docs/api/java/util/Properties.html)
247
- - Java's `PropertyResourceBundle` [documentation](https://docs.oracle.com/javase/9/docs/api/java/util/PropertyResourceBundle.html)
248
- - Java's Internationalization [Guide](https://docs.oracle.com/en/java/javase/18/intl/internationalization-overview.html)
249
- - Wikipedia's .properties [page](https://en.wikipedia.org/wiki/.properties)
250
-
251
- ### Special mention
252
-
253
- Thanks to [@calibr](https://github.com/calibr), the creator of [properties-file version 1.0](https://github.com/calibr/properties-file), for letting us use the [https://www.npmjs.com/package/properties-file](https://www.npmjs.com/package/properties-file) package name. We hope that it will make it easier to find our package.
1
+ # properties-file
2
+
3
+ [![License](https://img.shields.io/npm/l/make-coverage-badge.svg?color=brightgreen)](https://opensource.org/licenses/MIT)
4
+ [![Download Stats](https://img.shields.io/npm/dw/properties-file.svg?color=brightgreen)](https://www.npmjs.com/package/properties-file)
5
+ ![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)
6
+ ![Package Size](https://img.shields.io/badge/min%2Bgzip-1.1%20kB-brightgreen)
7
+ ![Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
8
+
9
+ `.properties` file parser, editor, formatter and bundler integrations.
10
+
11
+ ## Installation
12
+
13
+ > Doing a major version update? Check our [migration guides](./docs/migration/README.md).
14
+
15
+ Add the package as a dependency:
16
+
17
+ ```
18
+ npm install properties-file
19
+ ```
20
+
21
+ ## What's in it for me?
22
+
23
+ - A modern library written entirely in TypeScript that exactly reproduces the [Properties Java implementation](/assets/java-implementation.md).
24
+ - Works for both Node.js applications and browsers that support at least [ES5](https://www.w3schools.com/js/js_es5.asp).
25
+ - Flexible, tree-shakable APIs — import only what you need, and your bundler will exclude the rest:
26
+ - `getProperties` converts `.properties` content to a key-value pair object.
27
+ - `Properties` provides lossless parsing with a full data model — every element (properties, comments, blank lines, whitespace, duplicate keys) is preserved and can be round-tripped exactly or normalized via `format()` options.
28
+ - `PropertiesEditor` enables insertion, edition, and removal of entries while preserving formatting.
29
+ - `escapeKey` and `escapeValue` convert any content to `.properties` compatible format.
30
+ - Bundler integrations for Webpack, Rollup/Vite, esbuild, and Bun to import `.properties` files directly. See [BUNDLER.md](./docs/BUNDLER.md).
31
+ - **Tiny with 0 dependencies** — `getProperties` is only 1.1 kB min+gzip.
32
+ - **Runs everywhere** — compiled to ES5, works in any browser and on Node.js all the way back to v0.10 (2013). [Verified via Docker](./tests/node-compat/).
33
+ - **100% test coverage** based on the output from a Java implementation.
34
+ - Active maintenance (many popular `.properties` packages have been inactive for years). See our [detailed comparison](./docs/COMPARISON.md) with other packages.
35
+
36
+ ## Usage
37
+
38
+ We have put a lot of effort into incorporating [TSDoc](https://tsdoc.org/) into all our APIs. If you are unsure about how to use certain APIs provided in our examples, please check directly in your IDE.
39
+
40
+ ### `getProperties` (converting `.properties` to an object)
41
+
42
+ The most common use case for `.properties` files is for Node.js applications that need to read the file's content into a simple key-value pair object. Here is how this can be done with a single API call:
43
+
44
+ ```ts
45
+ import { readFileSync } from 'node:fs'
46
+ import { getProperties } from 'properties-file'
47
+
48
+ console.log(getProperties(readFileSync('hello-world.properties')))
49
+ ```
50
+
51
+ Output:
52
+
53
+ ```js
54
+ { hello: 'hello', world: 'world' }
55
+ ```
56
+
57
+ ### `Properties` (lossless parsing with full data model)
58
+
59
+ The `Properties` class parses a `.properties` file into a lossless data model where every element — properties, comments, blank lines — is preserved in order. This is useful when you need to inspect, analyze, or transform `.properties` files while retaining their exact structure.
60
+
61
+ ```ts
62
+ import { readFileSync } from 'node:fs'
63
+ import { PropertiesNodeType, Properties } from 'properties-file/parser'
64
+
65
+ const properties = new Properties(readFileSync('example.properties'))
66
+
67
+ // Access all nodes in file order (properties, comments, blank lines).
68
+ for (const node of properties.nodes) {
69
+ switch (node.type) {
70
+ case PropertiesNodeType.PROPERTY:
71
+ console.log(`${node.key} = ${node.value}`)
72
+ break
73
+ case PropertiesNodeType.COMMENT:
74
+ console.log(`Comment: ${node.delimiter}${node.body}`)
75
+ break
76
+ case PropertiesNodeType.BLANK:
77
+ console.log('(blank line)')
78
+ break
79
+ }
80
+ }
81
+
82
+ // Get a simple key-value object (last-wins for duplicate keys).
83
+ console.log(properties.toObject())
84
+
85
+ // Lossless round-trip: format() reproduces the exact original content.
86
+ console.log(properties.format() === readFileSync('example.properties', 'utf8')) // true
87
+ ```
88
+
89
+ #### Finding key collisions
90
+
91
+ ```ts
92
+ import { Properties } from 'properties-file/parser'
93
+
94
+ const properties = new Properties(
95
+ 'hello = hello1\nworld = world1\nworld = world2\nhello = hello2\nworld = world3'
96
+ )
97
+
98
+ const collisions = properties.getKeyCollisions()
99
+ collisions.forEach((collision) => {
100
+ const lines = collision.nodes.map((node) => node.startingLineNumber)
101
+ console.log(`Key '${collision.key}' appears on lines ${lines.join(', ')}`)
102
+ })
103
+
104
+ /**
105
+ * Outputs:
106
+ *
107
+ * Key 'hello' appears on lines 1, 4
108
+ * Key 'world' appears on lines 2, 3, 5
109
+ */
110
+ ```
111
+
112
+ #### Normalizing output
113
+
114
+ Passing options to `format()` produces a normalized version of the file with granular control over formatting:
115
+
116
+ ```ts
117
+ import { Properties } from 'properties-file/parser'
118
+
119
+ const properties = new Properties('# comment\n\n key : value\n key : updated')
120
+
121
+ console.log(
122
+ properties.format({
123
+ removeComments: true, // Strip all comments
124
+ removeBlankLines: true, // Strip all blank lines
125
+ removeLeadingWhitespace: true, // Strip indentation
126
+ deduplicateKeys: true, // Keep only last occurrence
127
+ separatorChar: '=', // Standardize separator
128
+ separatorLeading: ' ', // Space before =
129
+ separatorTrailing: ' ', // Space after =
130
+ })
131
+ )
132
+
133
+ /**
134
+ * Outputs:
135
+ *
136
+ * key = updated
137
+ */
138
+ ```
139
+
140
+ ### `PropertiesEditor` (editing `.properties` content)
141
+
142
+ The `PropertiesEditor` extends `Properties` with methods to insert, update, delete, and upsert entries while preserving formatting.
143
+
144
+ ```ts
145
+ import { PropertiesEditor } from 'properties-file/editor'
146
+
147
+ const properties = new PropertiesEditor('hello = hello\n# This is a comment\nworld = world')
148
+
149
+ properties.insertComment('This is a multiline\ncomment before `newKey3`')
150
+ properties.insert('newKey3', 'This is my third key')
151
+
152
+ properties.insert('newKey1', 'This is my first new key', {
153
+ referenceKey: 'newKey3',
154
+ position: 'before',
155
+ comment: 'Below are the new keys being edited',
156
+ commentDelimiter: '!',
157
+ })
158
+
159
+ properties.insert('newKey2', 'hello', {
160
+ referenceKey: 'newKey1',
161
+ position: 'after',
162
+ escapeUnicode: true,
163
+ })
164
+
165
+ properties.delete('hello')
166
+ properties.update('world', {
167
+ newValue: 'new world',
168
+ })
169
+ console.log(properties.format())
170
+
171
+ /**
172
+ * Outputs:
173
+ *
174
+ * # This is a comment
175
+ * world = new world
176
+ * ! Below are the new keys being edited
177
+ * newKey1 = This is my first new key
178
+ * newKey2 = hello
179
+ * # This is a multiline
180
+ * # comment before `newKey3`
181
+ * newKey3 = This is my third key
182
+ */
183
+ ```
184
+
185
+ The editor also provides `upsert` (update or insert) and `deleteAll` (remove all occurrences of a duplicate key). Check your IDE for all available methods and options via TSDoc.
186
+
187
+ ### Bundler Integrations
188
+
189
+ If you would like to import `.properties` directly using `import`, this package provides integrations for all major bundlers: **Webpack/Rspack**, **Rollup/Vite/Rolldown**, **esbuild**, and **Bun**.
190
+
191
+ See [BUNDLER.md](./docs/BUNDLER.md) for setup instructions and examples.
192
+
193
+ By adding these configurations you should now be able to import directly `.properties` files just like this:
194
+
195
+ ```ts
196
+ import { properties as helloWorld } from './hello-world.properties'
197
+
198
+ console.dir(helloWorld)
199
+ ```
200
+
201
+ Output:
202
+
203
+ ```json
204
+ { "hello": "world" }
205
+ ```
206
+
207
+ ## Why another `.properties` file package?
208
+
209
+ There are over 20 similar packages available, but most are abandoned, incomplete, or not compliant with the Java specification. See our [detailed comparison](./docs/COMPARISON.md) for benchmarks, compliance tests, and a feature matrix against the top 5 packages. The short version:
210
+
211
+ - **100% Java spec compliance** — the only package (alongside `properties-parser`) to pass all test cases.
212
+ - **3–7x faster** than alternatives on a 10,000-entry file.
213
+ - **Lossless data model** — no other package preserves comments, blank lines, whitespace, and duplicate keys for round-trip editing.
214
+
215
+ Unfortunately, the `.properties` file specification is not well-documented. One reason for this is that it was originally used in Java to store configurations. Today, most applications handle this using JSON, YAML, or other modern formats because these formats are more flexible.
216
+
217
+ ### So why `.properties` files?
218
+
219
+ While many options exist today to handle configurations, `.properties` files remain one of the best options to store localizable strings (also known as messages). On the Java side, `PropertyResourceBundle` is how most implementations handle localization today. Because of its simplicity and maturity, `.properties` files remain one of the best options today when it comes to internationalization (i18n):
220
+
221
+ | File format | Key/value based | Supports inline comments | Built for localization | Good linguistic tools support |
222
+ | ------------- | ---------------- | ------------------------ | ---------------------- | ----------------------------- |
223
+ | `.properties` | Yes | Yes | Yes (Resource Bundles) | Yes |
224
+ | `JSON` | No (can do more) | No (requires JSON5) | No | Depends on the schema |
225
+ | `YAML` | No (can do more) | Yes | No | Depends on the schema |
226
+
227
+ Having good JavaScript/TypeScript support for `.properties` files offers more internationalization (i18n) options.
228
+
229
+ ### How does this package work?
230
+
231
+ Our goal is to offer parity with the Java implementation, which is the closest thing to a specification for `.properties` files. The package provides two parsing paths:
232
+
233
+ 1. **`getProperties`** — a fast, functional parser optimized for the common case of converting `.properties` content to a key-value object. Uses `charCodeAt`-based scanning with zero-copy optimizations.
234
+
235
+ 2. **`Properties`** — a lossless parser that produces an ordered array of typed nodes (`PropertyNode`, `CommentNode`, `BlankLineNode`). Every element in the file is preserved, enabling exact round-trip reconstruction via `format()` and flexible normalization by passing options to `format()`.
236
+
237
+ Both parsers are fully compliant with the Java `Properties` specification and produce identical key-value output. Just like Java, if a Unicode-escaped character (`\u`) is malformed, an error will be thrown.
238
+
239
+ ## Contributing
240
+
241
+ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md) for project principles, architecture, code style, and development commands.
242
+
243
+ ## Additional references
244
+
245
+ - Java [Test Sandbox](https://codehs.com/sandbox/id/java-main-FObePj)
246
+ - Java's `Properties` class [documentation](https://docs.oracle.com/javase/9/docs/api/java/util/Properties.html)
247
+ - Java's `PropertyResourceBundle` [documentation](https://docs.oracle.com/javase/9/docs/api/java/util/PropertyResourceBundle.html)
248
+ - Java's Internationalization [Guide](https://docs.oracle.com/en/java/javase/18/intl/internationalization-overview.html)
249
+ - Wikipedia's .properties [page](https://en.wikipedia.org/wiki/.properties)
250
+
251
+ ### Special mention
252
+
253
+ Thanks to [@calibr](https://github.com/calibr), the creator of [properties-file version 1.0](https://github.com/calibr/properties-file), for letting us use the [https://www.npmjs.com/package/properties-file](https://www.npmjs.com/package/properties-file) package name. We hope that it will make it easier to find our package.
@@ -6,64 +6,88 @@ export type KeyValuePairSeparator = '=' | ':' | ' ';
6
6
  export type CommentDelimiter = '#' | '!';
7
7
  /** Options for {@link PropertiesEditor.insert}. */
8
8
  export type InsertOptions = {
9
- /** Key to insert before or after. */
9
+ /**
10
+ * Insert relative to this key (last occurrence). If the key is not found,
11
+ * the property is appended at the end.
12
+ */
10
13
  referenceKey?: string;
11
14
  /** Position relative to the reference key. Default: `'after'`. */
12
15
  position?: 'before' | 'after';
13
- /** Escape non-ASCII characters as `\\uXXXX`. Default: `false`. */
16
+ /** If `true`, escape non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
14
17
  escapeUnicode?: boolean;
15
- /** Separator character to use. Default: `'='`. */
18
+ /** Separator character to use between key and value. Default: `'='`. */
16
19
  separator?: KeyValuePairSeparator;
17
- /** Comment text to prepend (without delimiter). */
20
+ /**
21
+ * Comment text to prepend before the property. Supports multi-line: newlines
22
+ * in the string create separate comment nodes. Empty lines within the text
23
+ * become blank line nodes.
24
+ */
18
25
  comment?: string;
19
- /** Comment delimiter. Default: `'#'`. */
26
+ /** Delimiter character for the comment. Default: `'#'`. */
20
27
  commentDelimiter?: CommentDelimiter;
21
28
  };
22
29
  /** Options for {@link PropertiesEditor.insertComment}. */
23
30
  export type InsertCommentOptions = {
24
- /** Key to insert before or after. */
31
+ /**
32
+ * Insert relative to this key (last occurrence). If the key is not found,
33
+ * the comment is appended at the end.
34
+ */
25
35
  referenceKey?: string;
26
36
  /** Position relative to the reference key. Default: `'after'`. */
27
37
  position?: 'before' | 'after';
28
- /** Comment delimiter. Default: `'#'`. */
38
+ /** Delimiter character for the comment. Default: `'#'`. */
29
39
  commentDelimiter?: CommentDelimiter;
30
40
  };
31
41
  /** Options for {@link PropertiesEditor.insertBlankLine}. */
32
42
  export type InsertBlankLineOptions = {
33
- /** Key to insert before or after. */
43
+ /**
44
+ * Insert relative to this key (last occurrence). If the key is not found,
45
+ * the blank line is appended at the end.
46
+ */
34
47
  referenceKey?: string;
35
48
  /** Position relative to the reference key. Default: `'after'`. */
36
49
  position?: 'before' | 'after';
37
50
  };
38
51
  /** Options for {@link PropertiesEditor.update}. */
39
52
  export type UpdateOptions = {
40
- /** New value. */
53
+ /** Replacement value. When not set, the original value is preserved. */
41
54
  newValue?: string;
42
- /** New key (rename). */
55
+ /** Replacement key (rename). When not set, the original key is preserved. */
43
56
  newKey?: string;
44
- /** Escape non-ASCII characters as `\\uXXXX`. Default: `false`. */
57
+ /** If `true`, escape non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
45
58
  escapeUnicode?: boolean;
46
- /** New separator character. */
59
+ /** New separator character. When not set, the original separator is preserved. */
47
60
  separator?: KeyValuePairSeparator;
48
- /** New comment text (replaces all leading comment nodes). */
61
+ /**
62
+ * Replacement comment text. When set, all comment and blank line nodes immediately
63
+ * preceding the property (up to the previous property) are removed and replaced
64
+ * with the new comment. Supports multi-line via newlines in the string.
65
+ */
49
66
  newComment?: string;
50
- /** Comment delimiter. Default: `'#'`. */
67
+ /** Delimiter character for the new comment. Default: `'#'`. */
51
68
  commentDelimiter?: CommentDelimiter;
52
69
  };
53
70
  /** Options for {@link PropertiesEditor.upsert}. */
54
71
  export type UpsertOptions = {
55
- /** Escape non-ASCII characters as `\\uXXXX`. Default: `false`. */
72
+ /** If `true`, escape non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
56
73
  escapeUnicode?: boolean;
57
74
  /** Separator character. Default: `'='`. */
58
75
  separator?: KeyValuePairSeparator;
59
- /** Comment text for new properties. */
76
+ /**
77
+ * Comment text. When inserting a new property, this is prepended as a comment.
78
+ * When updating an existing property, this replaces the leading comment nodes.
79
+ */
60
80
  comment?: string;
61
- /** Comment delimiter. Default: `'#'`. */
81
+ /** Delimiter character for the comment. Default: `'#'`. */
62
82
  commentDelimiter?: CommentDelimiter;
63
83
  };
64
84
  /** Options for {@link PropertiesEditor.delete}. */
65
85
  export type DeleteOptions = {
66
- /** If `true`, also delete preceding comment and blank line nodes. Default: `true`. */
86
+ /**
87
+ * If `false`, only the property node itself is removed. If `true` (default),
88
+ * all comment and blank line nodes immediately preceding the property (up to
89
+ * the previous property) are also removed.
90
+ */
67
91
  deleteLeadingNodes?: boolean;
68
92
  };
69
93
  /**
@@ -84,30 +84,73 @@ export type KeyCollisions = {
84
84
  /** All property nodes with this key, in file order. */
85
85
  nodes: PropertyNode[];
86
86
  };
87
- /** Options for {@link Properties.format} when producing normalized output. */
87
+ /**
88
+ * Options for {@link Properties.format} when producing normalized output.
89
+ *
90
+ * When no options are passed to `format()`, the output is a lossless reconstruction
91
+ * of the original content. Passing any option triggers normalization, rebuilding
92
+ * property lines from their parsed fields.
93
+ */
88
94
  export type NormalizeOptions = {
89
- /** End-of-line character to use. Defaults to the detected EOL from the source. */
95
+ /** Override the end-of-line character. Defaults to the EOL detected from the source. */
90
96
  endOfLineCharacter?: '\n' | '\r\n';
91
- /** If `true`, remove all comment lines. Default: `false`. */
97
+ /** If `true`, remove all comment lines from the output. Default: `false`. */
92
98
  removeComments?: boolean;
93
- /** If `true`, remove all blank lines. Default: `false`. */
99
+ /** If `true`, remove all blank lines from the output. Default: `false`. */
94
100
  removeBlankLines?: boolean;
95
- /** If `true`, remove leading whitespace from all lines. Default: `false`. */
101
+ /** If `true`, strip leading whitespace from all property and comment lines. Default: `false`. */
96
102
  removeLeadingWhitespace?: boolean;
97
- /** If `true`, keep only the last occurrence of each key. Default: `false`. */
103
+ /**
104
+ * If `true`, keep only the last occurrence of each duplicate key (Java's last-wins
105
+ * semantics). Earlier occurrences and their leading comment/blank line nodes are
106
+ * removed from the output. Set `deduplicateKeysKeepLeadingNodes` to `true` to
107
+ * preserve the leading nodes. Default: `false`.
108
+ */
98
109
  deduplicateKeys?: boolean;
99
- /** Standardize the separator character. Original separators are preserved if not set. */
110
+ /**
111
+ * When `deduplicateKeys` is `true`, controls whether comment and blank line nodes
112
+ * preceding removed duplicates are preserved (`true`) or also removed (`false`).
113
+ * Default: `false` (leading nodes are removed along with the duplicate).
114
+ */
115
+ deduplicateKeysKeepLeadingNodes?: boolean;
116
+ /**
117
+ * Standardize the separator character across all properties. When set, every
118
+ * property is rewritten to use this separator. Original separators are preserved
119
+ * if not set. Use `' '` for whitespace-only separators (no `=` or `:`).
120
+ */
100
121
  separatorChar?: '=' | ':' | ' ';
101
- /** Whitespace to place before the separator character. */
122
+ /**
123
+ * Whitespace to place before the separator character (e.g. `' '` for `key = value`,
124
+ * `''` for `key=value`). When not set, each property's original leading whitespace
125
+ * is preserved.
126
+ */
102
127
  separatorLeading?: string;
103
- /** Whitespace to place after the separator character. */
128
+ /**
129
+ * Whitespace to place after the separator character (e.g. `' '` for `key = value`,
130
+ * `''` for `key=value`). When not set, each property's original trailing whitespace
131
+ * is preserved.
132
+ */
104
133
  separatorTrailing?: string;
105
- /** If `true`, escape all non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
134
+ /**
135
+ * If `true`, re-escape all non-ASCII characters as `\\uXXXX` sequences. Useful for
136
+ * producing ISO-8859-1 compatible output. Default: `false` (preserves original encoding).
137
+ */
106
138
  escapeUnicode?: boolean;
107
- /** If `true`, collapse multiline keys and values to single lines. Default: `false`. */
139
+ /**
140
+ * If `true`, collapse multiline keys and values (joined via `\\` line continuations)
141
+ * into single lines. Default: `false` (preserves original line structure).
142
+ */
108
143
  collapseMultiline?: boolean;
109
- /** Wrap keys at this character width using line continuations. `undefined` = no wrapping. */
144
+ /**
145
+ * Wrap keys at this character width using `\\` line continuations. Only applies to
146
+ * keys longer than the specified width. `\\uXXXX` sequences are never split across
147
+ * lines. `undefined` = no wrapping.
148
+ */
110
149
  wrapKeysAt?: number;
111
- /** Wrap values at this character width using line continuations. `undefined` = no wrapping. */
150
+ /**
151
+ * Wrap values at this character width using `\\` line continuations. Only applies to
152
+ * values longer than the specified width. `\\uXXXX` sequences are never split across
153
+ * lines. `undefined` = no wrapping.
154
+ */
112
155
  wrapValuesAt?: number;
113
156
  };
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"formatNormalized",{enumerable:!0,get:function(){return formatNormalized}});var _index=require("../escape/index.js"),BOM="\ufeff",wrapAtWidth=function(e,a){if(e.length<=a)return e;for(var r=[],i=0,t=e.length;i<t;){var o=Math.min(i+a,t);if(o<t)for(var n=0;n<6&&o-n>i;n++){var p=o-n;if(p+5<=t&&"\\"===e[p]&&"u"===e[p+1]){o=p;break}}r.push(e.slice(i,o)),i=o}return r.join("\\\n ")},rebuildPropertyLine=function(e,a){var r,i,t,o,n=!0===a.escapeUnicode,p=a.removeLeadingWhitespace?"":e.leadingWhitespace,s=n?(0,_index.escapeKey)(e.key,!0):e.escapedKey;void 0!==a.separatorChar?(i=void 0!==a.separatorLeading?a.separatorLeading:e.separatorLeading,t=" "===a.separatorChar?"":a.separatorChar,o=void 0!==a.separatorTrailing?a.separatorTrailing:e.separatorTrailing," "===a.separatorChar&&(i=void 0!==a.separatorLeading?a.separatorLeading:" ")):(i=void 0!==a.separatorLeading?a.separatorLeading:e.separatorLeading,t=null!==(r=e.separatorChar)&&void 0!==r?r:"",o=void 0!==a.separatorTrailing?a.separatorTrailing:e.separatorTrailing);var d=n?(0,_index.escapeValue)(e.value,!0):e.escapedValue;return void 0!==a.wrapKeysAt&&a.wrapKeysAt>0&&(s=wrapAtWidth(s,a.wrapKeysAt)),void 0!==a.wrapValuesAt&&a.wrapValuesAt>0&&(d=wrapAtWidth(d,a.wrapValuesAt)),"".concat(p).concat(s).concat(i).concat(t).concat(o).concat(d)},formatNormalized=function(e,a,r,i){var t,o,n=null!==(t=i.endOfLineCharacter)&&void 0!==t?t:r,p=void 0!==i.separatorChar||void 0!==i.separatorLeading||void 0!==i.separatorTrailing||!0===i.escapeUnicode||!0===i.collapseMultiline||void 0!==i.wrapKeysAt||void 0!==i.wrapValuesAt||!0===i.removeLeadingWhitespace;if(i.deduplicateKeys){var s={};o={};for(var d=e.length-1;d>=0;d--){var c=e[d];"property"!==c.type||s[c.key]||(s[c.key]=!0,o[d]=!0)}}for(var l=[],u=0;u<e.length;u++){var v=e[u];switch(v.type){case"comment":if(i.removeComments)continue;l.push(i.removeLeadingWhitespace?"".concat(v.delimiter).concat(v.body):v.rawLine);break;case"blank":if(i.removeBlankLines)continue;l.push(v.rawLine);break;case"property":if(o&&!o[u])continue;p?l.push(rebuildPropertyLine(v,i)):l.push(v.rawLines.join(n))}}return(a?BOM:"")+l.join(n)};
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"formatNormalized",{enumerable:!0,get:function(){return formatNormalized}});var _index=require("../escape/index.js"),BOM="\ufeff",wrapAtWidth=function(e,a){if(e.length<=a)return e;for(var r=[],i=0,t=e.length;i<t;){var o=Math.min(i+a,t);if(o<t)for(var n=0;n<6&&o-n>i;n++){var p=o-n;if(p+5<=t&&"\\"===e[p]&&"u"===e[p+1]){o=p;break}}r.push(e.slice(i,o)),i=o}return r.join("\\\n ")},rebuildPropertyLine=function(e,a){var r,i,t,o,n=!0===a.escapeUnicode,p=a.removeLeadingWhitespace?"":e.leadingWhitespace,s=n?(0,_index.escapeKey)(e.key,!0):e.escapedKey;void 0!==a.separatorChar?(i=void 0!==a.separatorLeading?a.separatorLeading:e.separatorLeading,t=" "===a.separatorChar?"":a.separatorChar,o=void 0!==a.separatorTrailing?a.separatorTrailing:e.separatorTrailing," "===a.separatorChar&&(i=void 0!==a.separatorLeading?a.separatorLeading:" ")):(i=void 0!==a.separatorLeading?a.separatorLeading:e.separatorLeading,t=null!==(r=e.separatorChar)&&void 0!==r?r:"",o=void 0!==a.separatorTrailing?a.separatorTrailing:e.separatorTrailing);var d=n?(0,_index.escapeValue)(e.value,!0):e.escapedValue;return void 0!==a.wrapKeysAt&&a.wrapKeysAt>0&&(s=wrapAtWidth(s,a.wrapKeysAt)),void 0!==a.wrapValuesAt&&a.wrapValuesAt>0&&(d=wrapAtWidth(d,a.wrapValuesAt)),"".concat(p).concat(s).concat(i).concat(t).concat(o).concat(d)},formatNormalized=function(e,a,r,i){var t,o,n=null!==(t=i.endOfLineCharacter)&&void 0!==t?t:r,p=void 0!==i.separatorChar||void 0!==i.separatorLeading||void 0!==i.separatorTrailing||!0===i.escapeUnicode||!0===i.collapseMultiline||void 0!==i.wrapKeysAt||void 0!==i.wrapValuesAt||!0===i.removeLeadingWhitespace;if(i.deduplicateKeys){for(var s={},d=[],c=e.length-1;c>=0;c--){var l=e[c];"property"===l.type&&(s[l.key]?d.push(c):s[l.key]=!0)}o={};var u=!0,v=!1,f=void 0;try{for(var h,y=d[Symbol.iterator]();!(u=(h=y.next()).done);u=!0){var g=h.value;if(o[g]=!0,!i.deduplicateKeysKeepLeadingNodes)for(var L=g-1;L>=0&&"property"!==e[L].type;L--)o[L]=!0}}catch(e){v=!0,f=e}finally{try{u||null==y.return||y.return()}finally{if(v)throw f}}}for(var m=[],w=0;w<e.length;w++)if(!o||!o[w]){var b=e[w];switch(b.type){case"comment":if(i.removeComments)continue;m.push(i.removeLeadingWhitespace?"".concat(b.delimiter).concat(b.body):b.rawLine);break;case"blank":if(i.removeBlankLines)continue;m.push(b.rawLine);break;case"property":p?m.push(rebuildPropertyLine(b,i)):m.push(b.rawLines.join(n))}}return(a?BOM:"")+m.join(n)};
@@ -6,64 +6,88 @@ export type KeyValuePairSeparator = '=' | ':' | ' ';
6
6
  export type CommentDelimiter = '#' | '!';
7
7
  /** Options for {@link PropertiesEditor.insert}. */
8
8
  export type InsertOptions = {
9
- /** Key to insert before or after. */
9
+ /**
10
+ * Insert relative to this key (last occurrence). If the key is not found,
11
+ * the property is appended at the end.
12
+ */
10
13
  referenceKey?: string;
11
14
  /** Position relative to the reference key. Default: `'after'`. */
12
15
  position?: 'before' | 'after';
13
- /** Escape non-ASCII characters as `\\uXXXX`. Default: `false`. */
16
+ /** If `true`, escape non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
14
17
  escapeUnicode?: boolean;
15
- /** Separator character to use. Default: `'='`. */
18
+ /** Separator character to use between key and value. Default: `'='`. */
16
19
  separator?: KeyValuePairSeparator;
17
- /** Comment text to prepend (without delimiter). */
20
+ /**
21
+ * Comment text to prepend before the property. Supports multi-line: newlines
22
+ * in the string create separate comment nodes. Empty lines within the text
23
+ * become blank line nodes.
24
+ */
18
25
  comment?: string;
19
- /** Comment delimiter. Default: `'#'`. */
26
+ /** Delimiter character for the comment. Default: `'#'`. */
20
27
  commentDelimiter?: CommentDelimiter;
21
28
  };
22
29
  /** Options for {@link PropertiesEditor.insertComment}. */
23
30
  export type InsertCommentOptions = {
24
- /** Key to insert before or after. */
31
+ /**
32
+ * Insert relative to this key (last occurrence). If the key is not found,
33
+ * the comment is appended at the end.
34
+ */
25
35
  referenceKey?: string;
26
36
  /** Position relative to the reference key. Default: `'after'`. */
27
37
  position?: 'before' | 'after';
28
- /** Comment delimiter. Default: `'#'`. */
38
+ /** Delimiter character for the comment. Default: `'#'`. */
29
39
  commentDelimiter?: CommentDelimiter;
30
40
  };
31
41
  /** Options for {@link PropertiesEditor.insertBlankLine}. */
32
42
  export type InsertBlankLineOptions = {
33
- /** Key to insert before or after. */
43
+ /**
44
+ * Insert relative to this key (last occurrence). If the key is not found,
45
+ * the blank line is appended at the end.
46
+ */
34
47
  referenceKey?: string;
35
48
  /** Position relative to the reference key. Default: `'after'`. */
36
49
  position?: 'before' | 'after';
37
50
  };
38
51
  /** Options for {@link PropertiesEditor.update}. */
39
52
  export type UpdateOptions = {
40
- /** New value. */
53
+ /** Replacement value. When not set, the original value is preserved. */
41
54
  newValue?: string;
42
- /** New key (rename). */
55
+ /** Replacement key (rename). When not set, the original key is preserved. */
43
56
  newKey?: string;
44
- /** Escape non-ASCII characters as `\\uXXXX`. Default: `false`. */
57
+ /** If `true`, escape non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
45
58
  escapeUnicode?: boolean;
46
- /** New separator character. */
59
+ /** New separator character. When not set, the original separator is preserved. */
47
60
  separator?: KeyValuePairSeparator;
48
- /** New comment text (replaces all leading comment nodes). */
61
+ /**
62
+ * Replacement comment text. When set, all comment and blank line nodes immediately
63
+ * preceding the property (up to the previous property) are removed and replaced
64
+ * with the new comment. Supports multi-line via newlines in the string.
65
+ */
49
66
  newComment?: string;
50
- /** Comment delimiter. Default: `'#'`. */
67
+ /** Delimiter character for the new comment. Default: `'#'`. */
51
68
  commentDelimiter?: CommentDelimiter;
52
69
  };
53
70
  /** Options for {@link PropertiesEditor.upsert}. */
54
71
  export type UpsertOptions = {
55
- /** Escape non-ASCII characters as `\\uXXXX`. Default: `false`. */
72
+ /** If `true`, escape non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
56
73
  escapeUnicode?: boolean;
57
74
  /** Separator character. Default: `'='`. */
58
75
  separator?: KeyValuePairSeparator;
59
- /** Comment text for new properties. */
76
+ /**
77
+ * Comment text. When inserting a new property, this is prepended as a comment.
78
+ * When updating an existing property, this replaces the leading comment nodes.
79
+ */
60
80
  comment?: string;
61
- /** Comment delimiter. Default: `'#'`. */
81
+ /** Delimiter character for the comment. Default: `'#'`. */
62
82
  commentDelimiter?: CommentDelimiter;
63
83
  };
64
84
  /** Options for {@link PropertiesEditor.delete}. */
65
85
  export type DeleteOptions = {
66
- /** If `true`, also delete preceding comment and blank line nodes. Default: `true`. */
86
+ /**
87
+ * If `false`, only the property node itself is removed. If `true` (default),
88
+ * all comment and blank line nodes immediately preceding the property (up to
89
+ * the previous property) are also removed.
90
+ */
67
91
  deleteLeadingNodes?: boolean;
68
92
  };
69
93
  /**
@@ -84,30 +84,73 @@ export type KeyCollisions = {
84
84
  /** All property nodes with this key, in file order. */
85
85
  nodes: PropertyNode[];
86
86
  };
87
- /** Options for {@link Properties.format} when producing normalized output. */
87
+ /**
88
+ * Options for {@link Properties.format} when producing normalized output.
89
+ *
90
+ * When no options are passed to `format()`, the output is a lossless reconstruction
91
+ * of the original content. Passing any option triggers normalization, rebuilding
92
+ * property lines from their parsed fields.
93
+ */
88
94
  export type NormalizeOptions = {
89
- /** End-of-line character to use. Defaults to the detected EOL from the source. */
95
+ /** Override the end-of-line character. Defaults to the EOL detected from the source. */
90
96
  endOfLineCharacter?: '\n' | '\r\n';
91
- /** If `true`, remove all comment lines. Default: `false`. */
97
+ /** If `true`, remove all comment lines from the output. Default: `false`. */
92
98
  removeComments?: boolean;
93
- /** If `true`, remove all blank lines. Default: `false`. */
99
+ /** If `true`, remove all blank lines from the output. Default: `false`. */
94
100
  removeBlankLines?: boolean;
95
- /** If `true`, remove leading whitespace from all lines. Default: `false`. */
101
+ /** If `true`, strip leading whitespace from all property and comment lines. Default: `false`. */
96
102
  removeLeadingWhitespace?: boolean;
97
- /** If `true`, keep only the last occurrence of each key. Default: `false`. */
103
+ /**
104
+ * If `true`, keep only the last occurrence of each duplicate key (Java's last-wins
105
+ * semantics). Earlier occurrences and their leading comment/blank line nodes are
106
+ * removed from the output. Set `deduplicateKeysKeepLeadingNodes` to `true` to
107
+ * preserve the leading nodes. Default: `false`.
108
+ */
98
109
  deduplicateKeys?: boolean;
99
- /** Standardize the separator character. Original separators are preserved if not set. */
110
+ /**
111
+ * When `deduplicateKeys` is `true`, controls whether comment and blank line nodes
112
+ * preceding removed duplicates are preserved (`true`) or also removed (`false`).
113
+ * Default: `false` (leading nodes are removed along with the duplicate).
114
+ */
115
+ deduplicateKeysKeepLeadingNodes?: boolean;
116
+ /**
117
+ * Standardize the separator character across all properties. When set, every
118
+ * property is rewritten to use this separator. Original separators are preserved
119
+ * if not set. Use `' '` for whitespace-only separators (no `=` or `:`).
120
+ */
100
121
  separatorChar?: '=' | ':' | ' ';
101
- /** Whitespace to place before the separator character. */
122
+ /**
123
+ * Whitespace to place before the separator character (e.g. `' '` for `key = value`,
124
+ * `''` for `key=value`). When not set, each property's original leading whitespace
125
+ * is preserved.
126
+ */
102
127
  separatorLeading?: string;
103
- /** Whitespace to place after the separator character. */
128
+ /**
129
+ * Whitespace to place after the separator character (e.g. `' '` for `key = value`,
130
+ * `''` for `key=value`). When not set, each property's original trailing whitespace
131
+ * is preserved.
132
+ */
104
133
  separatorTrailing?: string;
105
- /** If `true`, escape all non-ASCII characters as `\\uXXXX` sequences. Default: `false`. */
134
+ /**
135
+ * If `true`, re-escape all non-ASCII characters as `\\uXXXX` sequences. Useful for
136
+ * producing ISO-8859-1 compatible output. Default: `false` (preserves original encoding).
137
+ */
106
138
  escapeUnicode?: boolean;
107
- /** If `true`, collapse multiline keys and values to single lines. Default: `false`. */
139
+ /**
140
+ * If `true`, collapse multiline keys and values (joined via `\\` line continuations)
141
+ * into single lines. Default: `false` (preserves original line structure).
142
+ */
108
143
  collapseMultiline?: boolean;
109
- /** Wrap keys at this character width using line continuations. `undefined` = no wrapping. */
144
+ /**
145
+ * Wrap keys at this character width using `\\` line continuations. Only applies to
146
+ * keys longer than the specified width. `\\uXXXX` sequences are never split across
147
+ * lines. `undefined` = no wrapping.
148
+ */
110
149
  wrapKeysAt?: number;
111
- /** Wrap values at this character width using line continuations. `undefined` = no wrapping. */
150
+ /**
151
+ * Wrap values at this character width using `\\` line continuations. Only applies to
152
+ * values longer than the specified width. `\\uXXXX` sequences are never split across
153
+ * lines. `undefined` = no wrapping.
154
+ */
112
155
  wrapValuesAt?: number;
113
156
  };
@@ -1 +1 @@
1
- import{escapeKey,escapeValue}from"../escape/index.js";var BOM="\ufeff",wrapAtWidth=function(a,e){if(a.length<=e)return a;for(var r=[],i=0,t=a.length;i<t;){var o=Math.min(i+e,t);if(o<t)for(var n=0;n<6&&o-n>i;n++){var p=o-n;if(p+5<=t&&"\\"===a[p]&&"u"===a[p+1]){o=p;break}}r.push(a.slice(i,o)),i=o}return r.join("\\\n ")},rebuildPropertyLine=function(a,e){var r,i,t,o,n=!0===e.escapeUnicode,p=e.removeLeadingWhitespace?"":a.leadingWhitespace,s=n?escapeKey(a.key,!0):a.escapedKey;void 0!==e.separatorChar?(i=void 0!==e.separatorLeading?e.separatorLeading:a.separatorLeading,t=" "===e.separatorChar?"":e.separatorChar,o=void 0!==e.separatorTrailing?e.separatorTrailing:a.separatorTrailing," "===e.separatorChar&&(i=void 0!==e.separatorLeading?e.separatorLeading:" ")):(i=void 0!==e.separatorLeading?e.separatorLeading:a.separatorLeading,t=null!==(r=a.separatorChar)&&void 0!==r?r:"",o=void 0!==e.separatorTrailing?e.separatorTrailing:a.separatorTrailing);var c=n?escapeValue(a.value,!0):a.escapedValue;return void 0!==e.wrapKeysAt&&e.wrapKeysAt>0&&(s=wrapAtWidth(s,e.wrapKeysAt)),void 0!==e.wrapValuesAt&&e.wrapValuesAt>0&&(c=wrapAtWidth(c,e.wrapValuesAt)),"".concat(p).concat(s).concat(i).concat(t).concat(o).concat(c)};export var formatNormalized=function(a,e,r,i){var t,o,n=null!==(t=i.endOfLineCharacter)&&void 0!==t?t:r,p=void 0!==i.separatorChar||void 0!==i.separatorLeading||void 0!==i.separatorTrailing||!0===i.escapeUnicode||!0===i.collapseMultiline||void 0!==i.wrapKeysAt||void 0!==i.wrapValuesAt||!0===i.removeLeadingWhitespace;if(i.deduplicateKeys){var s={};o={};for(var c=a.length-1;c>=0;c--){var d=a[c];"property"!==d.type||s[d.key]||(s[d.key]=!0,o[c]=!0)}}for(var l=[],v=0;v<a.length;v++){var u=a[v];switch(u.type){case"comment":if(i.removeComments)continue;l.push(i.removeLeadingWhitespace?"".concat(u.delimiter).concat(u.body):u.rawLine);break;case"blank":if(i.removeBlankLines)continue;l.push(u.rawLine);break;case"property":if(o&&!o[v])continue;p?l.push(rebuildPropertyLine(u,i)):l.push(u.rawLines.join(n))}}return(e?BOM:"")+l.join(n)};
1
+ import{escapeKey,escapeValue}from"../escape/index.js";var BOM="\ufeff",wrapAtWidth=function(e,a){if(e.length<=a)return e;for(var r=[],i=0,t=e.length;i<t;){var o=Math.min(i+a,t);if(o<t)for(var n=0;n<6&&o-n>i;n++){var p=o-n;if(p+5<=t&&"\\"===e[p]&&"u"===e[p+1]){o=p;break}}r.push(e.slice(i,o)),i=o}return r.join("\\\n ")},rebuildPropertyLine=function(e,a){var r,i,t,o,n=!0===a.escapeUnicode,p=a.removeLeadingWhitespace?"":e.leadingWhitespace,s=n?escapeKey(e.key,!0):e.escapedKey;void 0!==a.separatorChar?(i=void 0!==a.separatorLeading?a.separatorLeading:e.separatorLeading,t=" "===a.separatorChar?"":a.separatorChar,o=void 0!==a.separatorTrailing?a.separatorTrailing:e.separatorTrailing," "===a.separatorChar&&(i=void 0!==a.separatorLeading?a.separatorLeading:" ")):(i=void 0!==a.separatorLeading?a.separatorLeading:e.separatorLeading,t=null!==(r=e.separatorChar)&&void 0!==r?r:"",o=void 0!==a.separatorTrailing?a.separatorTrailing:e.separatorTrailing);var d=n?escapeValue(e.value,!0):e.escapedValue;return void 0!==a.wrapKeysAt&&a.wrapKeysAt>0&&(s=wrapAtWidth(s,a.wrapKeysAt)),void 0!==a.wrapValuesAt&&a.wrapValuesAt>0&&(d=wrapAtWidth(d,a.wrapValuesAt)),"".concat(p).concat(s).concat(i).concat(t).concat(o).concat(d)};export var formatNormalized=function(e,a,r,i){var t,o,n=null!==(t=i.endOfLineCharacter)&&void 0!==t?t:r,p=void 0!==i.separatorChar||void 0!==i.separatorLeading||void 0!==i.separatorTrailing||!0===i.escapeUnicode||!0===i.collapseMultiline||void 0!==i.wrapKeysAt||void 0!==i.wrapValuesAt||!0===i.removeLeadingWhitespace;if(i.deduplicateKeys){for(var s={},d=[],c=e.length-1;c>=0;c--){var l=e[c];"property"===l.type&&(s[l.key]?d.push(c):s[l.key]=!0)}o={};var v=!0,u=!1,h=void 0;try{for(var f,y=d[Symbol.iterator]();!(v=(f=y.next()).done);v=!0){var g=f.value;if(o[g]=!0,!i.deduplicateKeysKeepLeadingNodes)for(var L=g-1;L>=0&&"property"!==e[L].type;L--)o[L]=!0}}catch(e){u=!0,h=e}finally{try{v||null==y.return||y.return()}finally{if(u)throw h}}}for(var m=[],w=0;w<e.length;w++)if(!o||!o[w]){var A=e[w];switch(A.type){case"comment":if(i.removeComments)continue;m.push(i.removeLeadingWhitespace?"".concat(A.delimiter).concat(A.body):A.rawLine);break;case"blank":if(i.removeBlankLines)continue;m.push(A.rawLine);break;case"property":p?m.push(rebuildPropertyLine(A,i)):m.push(A.rawLines.join(n))}}return(a?BOM:"")+m.join(n)};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "properties-file",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": ".properties file parser, editor, formatter and bundler integrations.",
5
5
  "keywords": [
6
6
  ".properties",