@vazen-ai/toml 0.0.0-development.0 → 0.2.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/CHANGELOG.md +80 -0
- package/LICENSING.md +4 -1
- package/README.md +155 -8
- package/dist/index.d.mts +5948 -70
- package/dist/index.mjs +5719 -7058
- package/package.json +21 -12
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Changes to the `@vazen-ai/toml` npm package. Package versions are independent of
|
|
4
|
+
the Vazen TOML file format's `schema_version`.
|
|
5
|
+
|
|
6
|
+
<!-- Each version repeats the Added, Changed and Fixed headings. -->
|
|
7
|
+
<!-- markdownlint-configure-file { "MD024": { "siblings_only": true } } -->
|
|
8
|
+
|
|
9
|
+
## [Unreleased]
|
|
10
|
+
|
|
11
|
+
## [0.2.1] - 2026-10-08
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Fix the npm release workflow, which stopped before publishing 0.2.0. The
|
|
16
|
+
package code is unchanged from 0.2.0.
|
|
17
|
+
|
|
18
|
+
## [0.2.0] - 2026-10-06
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Read PSA tray, case, display and alternate merchandising styles as products
|
|
23
|
+
with their own packaging dimensions and unit counts.
|
|
24
|
+
- Return structured processing messages alongside the project and source from
|
|
25
|
+
file readers. PSA messages report recoverable problems; TOML and JSON readers
|
|
26
|
+
return an empty list. Writers do not store messages in converted files.
|
|
27
|
+
- Include this changelog in the npm package.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Require Effect 4.0.0 or a later 4.x release as a peer dependency. Exported
|
|
32
|
+
schemas and errors use Effect 4 types, including `SchemaError` in place of
|
|
33
|
+
`ParseError`. Effect schema decoding uses `Result` instead of `Either`.
|
|
34
|
+
- Rename the PSA records API's `compromises` field to `messages`, and
|
|
35
|
+
`PsaCompromise` to `PsaMessage`.
|
|
36
|
+
- Reduce temporary allocations when reading PSA cells and writing PSA bytes.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- Match PSA positions using the declared UPC, ID or combined primary key, and
|
|
41
|
+
preserve unused position identifiers through TOML and JSON round trips. Keep
|
|
42
|
+
separate PSA product rows distinct when writing.
|
|
43
|
+
- Keep reserved PSA text as text through JSON round trips. Distinguish TOML date
|
|
44
|
+
kinds when matching product selectors.
|
|
45
|
+
- Read integer PSA codes written as decimals, such as `0.00`.
|
|
46
|
+
- Refuse ambiguous Windows-1252 output that would read back as different UTF-8
|
|
47
|
+
text. Preserve Windows-1252 bytes `0x80` to `0x9F` on every supported Node.js
|
|
48
|
+
version.
|
|
49
|
+
- Reject `__proto__` keys when reading or writing TOML and JSON, instead of
|
|
50
|
+
allowing prototype changes or silently losing data.
|
|
51
|
+
|
|
52
|
+
## [0.1.0] - 2026-09-29
|
|
53
|
+
|
|
54
|
+
`@vazen-ai/toml` 0.1.0 is the first release of the package. It reads and writes
|
|
55
|
+
[Vazen TOML](https://toml.vazen.com/) 0.3.0 files, `vazen/spec` and
|
|
56
|
+
`vazen/layout`, as TOML or as JSON. It reads ProSpace PSA files of any version,
|
|
57
|
+
and writes PSA 2017.1.0 to 2024.4.0. Each file reads as the tables of a 0.3.0
|
|
58
|
+
file. A writer writes 0.3.0, or PSA 2024.4.0, unless another version is asked
|
|
59
|
+
for.
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npm install @vazen-ai/toml
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### What reading does not check
|
|
66
|
+
|
|
67
|
+
Reading checks the shape of a file. It does not check the specification's rules
|
|
68
|
+
of a whole file, nor its spatial rules. A project read from a PSA file drops
|
|
69
|
+
what the records reader lists as compromises, such as a cell its column could
|
|
70
|
+
not read; `decodePsaDataFromPsaFile` shows them.
|
|
71
|
+
[The package README](https://github.com/vazen-ai/toml/blob/main/typescript/README.md)
|
|
72
|
+
says what each function reads and writes, and
|
|
73
|
+
[the PSA README](https://github.com/vazen-ai/toml/blob/main/typescript/src/psa/README.md)
|
|
74
|
+
says which values the PSA reader loses and which the writer keeps.
|
|
75
|
+
|
|
76
|
+
### Requirements
|
|
77
|
+
|
|
78
|
+
The package is ESM only, for Node.js 24 or later. It needs Effect 3.14.8 or a
|
|
79
|
+
later 3.x release as a peer dependency. This release was published by hand and
|
|
80
|
+
carries no provenance.
|
package/LICENSING.md
CHANGED
|
@@ -20,4 +20,7 @@ version of the format, or your own product, as Vazen TOML, and do not suggest
|
|
|
20
20
|
that Vazen endorses you.
|
|
21
21
|
|
|
22
22
|
ProSpace, Blue Yonder, .psa and other third-party names are trademarks of their
|
|
23
|
-
respective owners. Vazen is not affiliated with or endorsed by Blue Yonder.
|
|
23
|
+
respective owners. Vazen is not affiliated with or endorsed by Blue Yonder. PSA
|
|
24
|
+
support was built from PSA files that customers supplied or that were published
|
|
25
|
+
online; column and value names follow ProSpace's field definitions. No Blue
|
|
26
|
+
Yonder software was used.
|
package/README.md
CHANGED
|
@@ -1,17 +1,164 @@
|
|
|
1
1
|
# @vazen-ai/toml
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@vazen-ai/toml` reads and writes [Vazen TOML](https://toml.vazen.com/) 0.3.0
|
|
4
|
+
files, `vazen/spec` and `vazen/layout`, as TOML or as JSON. It reads ProSpace
|
|
5
|
+
PSA files of any version, and writes the versions `PsaVersion` lists, 2017.1.0
|
|
6
|
+
to 2024.4.0. Each file reads as the tables of a 0.3.0 file. A writer writes
|
|
7
|
+
0.3.0, or PSA 2024.4.0, unless another version is asked for.
|
|
8
|
+
[Reading and writing](#reading-and-writing) says what each function reads and
|
|
9
|
+
writes, and what reading does not check.
|
|
10
|
+
|
|
11
|
+
The [changelog](CHANGELOG.md) records package changes separately from the file
|
|
12
|
+
format's versions.
|
|
4
13
|
|
|
5
14
|
```js
|
|
6
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
decodeVazenProjectFromTomlFile,
|
|
17
|
+
encodeJsonFileFromVazenProject,
|
|
18
|
+
} from '@vazen-ai/toml';
|
|
19
|
+
|
|
20
|
+
const { project, source, messages } =
|
|
21
|
+
decodeVazenProjectFromTomlFile(`schema = "vazen/spec"
|
|
22
|
+
schema_version = "0.3.0"
|
|
23
|
+
|
|
24
|
+
[[products]]
|
|
25
|
+
name = "Vazen Planflakes breakfast cereal 400 g"
|
|
26
|
+
gtin = "884400062451"
|
|
27
|
+
brand = "Vazen"
|
|
7
28
|
|
|
8
|
-
|
|
9
|
-
|
|
29
|
+
[[fixtures]]
|
|
30
|
+
|
|
31
|
+
[[fixtures.equipment]]
|
|
32
|
+
type = "shelf"
|
|
33
|
+
|
|
34
|
+
[[fixtures.equipment.sites]]
|
|
35
|
+
product = { gtin = "884400062451" }
|
|
36
|
+
facings = { wide = 3, deep = 4 }
|
|
37
|
+
`);
|
|
38
|
+
console.log(project.fixtures[0].equipment[0].sites[0].facings.wide);
|
|
39
|
+
// 3
|
|
40
|
+
console.log(source);
|
|
41
|
+
// { declaredVersion: '0.3.0', format: 'vazen-toml' }
|
|
42
|
+
console.log(messages);
|
|
43
|
+
// []
|
|
44
|
+
console.log(encodeJsonFileFromVazenProject({ project }).includes('"wide": 3'));
|
|
45
|
+
// true
|
|
10
46
|
```
|
|
11
47
|
|
|
12
|
-
|
|
48
|
+
## What a project holds
|
|
49
|
+
|
|
50
|
+
A project is the tables of a 0.3.0 file, `VazenTomlProjectV0_3_0`: `products`
|
|
51
|
+
and `fixtures`, each fixture's `equipment`, and each piece of equipment's
|
|
52
|
+
`sites`. When the file gives no value for a key, the key is absent. Keys the
|
|
53
|
+
specification does not define sit beside the standard keys, as in the file. A
|
|
54
|
+
reader returns `{ project, source, messages }`. The source gives the file's
|
|
55
|
+
format and declared version. The messages are structured findings from reading
|
|
56
|
+
or processing the project, with a `_tag` identifying each kind and details such
|
|
57
|
+
as affected records and columns. An empty list means none were reported. Writers
|
|
58
|
+
write the project alone, so these messages are not stored in converted files.
|
|
59
|
+
|
|
60
|
+
Readers return data that satisfies the project schema. This checks field types
|
|
61
|
+
and allowed values, not full planogram validity or spatial rules. The schemas
|
|
62
|
+
refuse an own `__proto__` key anywhere in a project, when reading or writing.
|
|
63
|
+
This keeps attribute keys safe to copy between JavaScript objects.
|
|
64
|
+
|
|
65
|
+
## JSON
|
|
66
|
+
|
|
67
|
+
The tables also read and write as JSON, in a `.vazen.json` file. The JSON has
|
|
68
|
+
the same keys and the same values. JSON has no date, so the JSON writer writes a
|
|
69
|
+
date as text, such as `"2026-09-27T09:30:00.000Z"`, `"2026-09-27"` or
|
|
70
|
+
`"09:30:00.000"`. The JSON reader reads text in exactly that form as a date, but
|
|
71
|
+
only in an attribute or a product selector. Text under a `_psa__` key stays
|
|
72
|
+
text, since it holds a PSA cell, and so does a selector's text under a product's
|
|
73
|
+
standard key, such as `name`, since the product's is text. So a `label` of
|
|
74
|
+
`"2026-09-27"` and a `label` of the date `2026-09-27` both read back as the
|
|
75
|
+
date. A selector for the text then matches both products, and the PSA writer
|
|
76
|
+
refuses it. JSON cannot hold `nan` or `inf`, so the JSON writer refuses them.
|
|
77
|
+
The JSON reader refuses an integer beyond JavaScript's safe range, as the TOML
|
|
78
|
+
reader does.
|
|
79
|
+
|
|
80
|
+
## PSA files
|
|
81
|
+
|
|
82
|
+
A PSA file reads as the tables of a 0.3.0 layout. Each planogram is a fixture,
|
|
83
|
+
each fixture row is its equipment, and each position is a site. A product that a
|
|
84
|
+
position places as a tray, a case, a display or an alternate also reads as one
|
|
85
|
+
more product for each of those styles, as the specification asks. Each one has
|
|
86
|
+
the style as its `form`, the style's dimensions, and the number of units it
|
|
87
|
+
holds as `_vazen__unit_count`. When written, they go back onto the same PSA
|
|
88
|
+
product row. Every length is in millimetres. A value with a standard key takes
|
|
89
|
+
that key. Every other value the file gives becomes a `_psa__` key on its object,
|
|
90
|
+
unless the column's default already implies it. With no reported messages, the
|
|
91
|
+
project writes back as the same PSA records, also after a trip through TOML or
|
|
92
|
+
JSON.
|
|
93
|
+
|
|
94
|
+
The PSA bridge matches products using the project's primary key: UPC alone, ID
|
|
95
|
+
alone, or the exact pair for Both. An absent primary-key cell defaults to UPC.
|
|
96
|
+
Identifier text is compared exactly, and a missing component compares as empty.
|
|
97
|
+
Both may have one empty component; each placed product and position must have at
|
|
98
|
+
least one identifier. Duplicate primary keys and positions with no match are
|
|
99
|
+
refused. There is no fallback to the secondary identifier.
|
|
100
|
+
|
|
101
|
+
When a position's unused identifier differs from its product's, its site keeps
|
|
102
|
+
the original cell in `_psa__id` or `_psa__upc`; an empty string means a blank
|
|
103
|
+
cell. These attributes survive TOML and JSON and write back to the position. An
|
|
104
|
+
export is refused if an edit makes them conflict with the selected product under
|
|
105
|
+
the current primary key.
|
|
106
|
+
|
|
107
|
+
```js
|
|
108
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
109
|
+
import {
|
|
110
|
+
decodeVazenProjectFromPsaFile,
|
|
111
|
+
encodeTomlFileFromVazenProject,
|
|
112
|
+
} from '@vazen-ai/toml';
|
|
113
|
+
|
|
114
|
+
const { project } = decodeVazenProjectFromPsaFile(
|
|
115
|
+
readFileSync('end-of-aisle.psa'),
|
|
116
|
+
);
|
|
117
|
+
writeFileSync(
|
|
118
|
+
'end-of-aisle.vazen.toml',
|
|
119
|
+
encodeTomlFileFromVazenProject({ project }),
|
|
120
|
+
);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
[Read and convert ProSpace PSA planogram files](https://toml.vazen.com/psa)
|
|
124
|
+
shows each conversion with a made-up PSA file to try.
|
|
125
|
+
|
|
126
|
+
## Reading and writing
|
|
127
|
+
|
|
128
|
+
Each format has a pair of file functions. `decodeVazenProjectFromTomlFile` and
|
|
129
|
+
`encodeTomlFileFromVazenProject` read and write TOML text.
|
|
130
|
+
`decodeVazenProjectFromJsonFile` and `encodeJsonFileFromVazenProject` read and
|
|
131
|
+
write JSON text. `decodeVazenProjectFromPsaFile` and
|
|
132
|
+
`encodePsaFileFromVazenProject` read and write PSA bytes. The TOML and JSON
|
|
133
|
+
readers take the versions `VazenVersion` lists. The PSA reader takes a file of
|
|
134
|
+
any version on a best-effort basis. Recoverable problems, such as an unreadable
|
|
135
|
+
cell treated as empty or an unfamiliar row width, are reported in `messages`.
|
|
136
|
+
Reading fails when it cannot produce a project that satisfies the schema. The
|
|
137
|
+
TOML and JSON writers write 0.3.0. The PSA writer writes 2024.4.0. The `version`
|
|
138
|
+
option names another version that `VazenVersion` or `PsaVersion` lists:
|
|
139
|
+
`encodePsaFileFromVazenProject({ project, version: '2017.2.0' })`. A writer
|
|
140
|
+
refuses a project that a reader would refuse as a file. The PSA writer also
|
|
141
|
+
refuses a value that a column of the named version cannot hold. Each function
|
|
142
|
+
throws a `SchemaError` saying what it could not read or write.
|
|
143
|
+
|
|
144
|
+
The Effect schemas behind the file functions are exported for a caller who wants
|
|
145
|
+
a `Result` or an `Effect`: `VazenProjectFromTomlText`,
|
|
146
|
+
`VazenProjectFromJsonText`, `VazenProjectFromPsaBytes`,
|
|
147
|
+
`VazenProjectFromPsaText` and `VazenProjectFromPsaData`. Each schema reads a
|
|
148
|
+
file into `VazenProject`. In a `VazenProject`, an optional value is an Effect
|
|
149
|
+
`Option`, the keys the specification does not define live in each object's
|
|
150
|
+
`attributes`, and `source` and `messages` are part of the project. So the PSA
|
|
151
|
+
schemas write the version of the PSA file the project came from, when that
|
|
152
|
+
version can hold the project.
|
|
13
153
|
|
|
14
|
-
|
|
15
|
-
|
|
154
|
+
The functions above read a file as a project. To edit the columns of a PSA file,
|
|
155
|
+
read its records instead. `decodePsaDataFromPsaFile` returns `PsaData`, the rows
|
|
156
|
+
of the file as records. `encodePsaFileFromPsaData` writes the records back to a
|
|
157
|
+
file.
|
|
158
|
+
[The PSA README](https://github.com/vazen-ai/toml/blob/main/typescript/src/psa/README.md)
|
|
159
|
+
says which values the reader loses and which values the writer keeps.
|
|
16
160
|
|
|
17
|
-
|
|
161
|
+
The package is ESM only, for Node.js 24 or later. It needs Effect 4.0.0 or a
|
|
162
|
+
later 4.x release as a peer dependency. To work on the package, run `npm ci`
|
|
163
|
+
then `npm run verify` here. Licensing is in
|
|
164
|
+
[LICENSING.md](https://github.com/vazen-ai/toml/blob/main/LICENSING.md).
|