jxcel 0.1.0__tar.gz

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.
jxcel-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mahmoud Ehab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,5 @@
1
+ include RELEASE_NOTES.md
2
+ prune tests
3
+ prune security-poc
4
+ prune .github
5
+ exclude AGENTS.md
jxcel-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: jxcel
3
+ Version: 0.1.0
4
+ Summary: A cross-platform CLI for converting JSON datasets into Excel workbooks
5
+ Author: Mahmoud Ehab
6
+ License-Expression: MIT
7
+ Project-URL: Source, https://github.com/abutaha7000d/jxcel
8
+ Keywords: json,excel,xlsx,cli,converter
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Environment :: Console
11
+ Classifier: Intended Audience :: End Users/Desktop
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Topic :: Utilities
19
+ Requires-Python: >=3.11
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: openpyxl<4,>=3.1.5
23
+ Dynamic: license-file
24
+
25
+ # jxcel
26
+
27
+ `jxcel` is a cross-platform command-line application for converting JSON files into formatted Excel `.xlsx` workbooks. It discovers tabular object arrays in general JSON documents; it has no fixed columns or domain-specific assumptions.
28
+
29
+ ## Development status
30
+
31
+ The converter is functional. JSON loading and validation, dataset discovery, schema planning and value preparation, workbook generation with validated publication, and command-line integration are implemented in `src/jxcel/`. The package has not been published.
32
+
33
+ Current cross-platform release verification passed in GitHub Actions run [41933979297](https://github.com/AbuTaha7000D/jxcel/actions/runs/41933979297) on commit `6d2e5e3f3f0b9cb4a0b7985847a496be744cc1e7`. All 12 Linux, Windows, and macOS × Python 3.11–3.14 jobs passed. Each ran the full 309-test suite and 25 CLI acceptance checks; Windows skipped three POSIX-only permission tests. The workflow also built and inspected wheel and source distributions, installed them in separate environments, and verified pipx installation.
34
+
35
+ The earlier Phase 8 run [41666703215](https://github.com/AbuTaha7000D/jxcel/actions/runs/41666703215) validated commit `f351669e6ed5ef072eb888e9a2f2f85401832210` on Windows and macOS with the original 299-test suite.
36
+
37
+ Release notes for version `0.1.0` are in [RELEASE_NOTES.md](https://github.com/AbuTaha7000D/jxcel/blob/main/RELEASE_NOTES.md).
38
+
39
+ ## Requirements
40
+
41
+ - Python 3.11 or newer is declared. Python 3.11, 3.12, 3.13, and 3.14 have all been exercised on Ubuntu 24.04, Windows 2025, and macOS 15 in run 41933979297.
42
+ - Runtime dependencies: the Python standard library and `openpyxl`.
43
+ - Linux, Windows, and macOS are intended targets. All three have been exercised: Linux locally, and Windows and macOS on GitHub-hosted runners in Phase 8.
44
+
45
+ ## Installation
46
+
47
+ A package distribution is not published yet. From a local checkout:
48
+
49
+ ```bash
50
+ python -m pip install .
51
+ ```
52
+
53
+ This command was verified on Linux in an isolated virtual environment and on the Windows and macOS CI runners in Phase 8. The build uses isolation, so it needs access to a package index or a populated build-dependency cache; an offline install fails if the required `setuptools` build dependency is unavailable.
54
+
55
+ An isolated installation from the checkout was also verified with `pipx`: 1.18.11 on Linux and 1.18.12 on the Windows and macOS CI runners.
56
+
57
+ ```bash
58
+ pipx install .
59
+ ```
60
+
61
+ Both commands install a `jxcel` command that points at `jxcel.cli:main`. Command availability, the isolated `pipx` command path, and execution from outside the checkout were verified on Linux, Windows, and macOS.
62
+
63
+ ## Usage
64
+
65
+ Exactly one input source is required: positional `INPUT` or `-i/--input PATH`.
66
+
67
+ ```bash
68
+ jxcel data.json
69
+ jxcel -i data.json
70
+ jxcel /path/to/data.json
71
+ jxcel -i /path/to/data.json -o result.xlsx
72
+ ```
73
+
74
+ By default, the output is written beside the input with an `.xlsx` suffix, so `data.json` produces `data.xlsx`. The output parent directory must already exist; jxcel never creates directories.
75
+
76
+ Existing output files are preserved unless `--overwrite` is supplied:
77
+
78
+ ```bash
79
+ jxcel data.json --overwrite
80
+ ```
81
+
82
+ Without `--overwrite`, an existing destination is an error. With it, jxcel builds and validates a temporary workbook first, then replaces the destination through the approved publication path. jxcel does not claim crash durability or stronger atomicity than the operating system and filesystem provide.
83
+
84
+ No-overwrite publication creates the destination with a same-directory hard link, so the temporary and destination files stay on one filesystem. Some filesystems do not support hard links, including FAT32/exFAT and some network or container mounts. On such filesystems, no-overwrite publication fails with exit status 1 and an explicit error. jxcel does not fall back to rename or replace, because that fallback could destroy a destination created concurrently. Overwrite publication uses the operating system's replace operation and depends on that filesystem's support. Hard-link behavior was exercised on Linux `tmpfs` and on the Windows and macOS runner temporary filesystems; other filesystem types, including FAT32/exFAT and network mounts, were not tested.
85
+
86
+ ## Input validation
87
+
88
+ jxcel reads the input as UTF-8 and accepts an optional UTF-8 BOM. Empty or whitespace-only files, malformed JSON, invalid UTF-8, and trailing content after the JSON value are rejected with exit status 1 and a path-aware error. Malformed JSON reports the line and column; invalid UTF-8 reports the byte offset.
89
+
90
+ Object keys must be unique at every level. Duplicate keys are rejected even when one is written with an escape such as `\u0061`, because it decodes to the same key; the same key in separate objects is allowed. `NaN`, `Infinity`, and `-Infinity` are rejected as non-standard JSON constants. JSON real numbers must be finite: tokens that overflow a Python float or underflow a nonzero value to zero are rejected. Integers decode as Python integers, subject to Python's configured integer-string conversion limit.
91
+
92
+ The loader does not restrict the JSON root category: objects, arrays, strings, numbers, booleans, and `null` are all accepted, subject to the validation above. Dataset discovery then treats a root that is not an object or array as `unsupported_root`. Discovery reports an empty array outside dataset records as `empty_array`, and an empty object outside arrays as `empty_object`; neither is an exportable dataset. `--list` and `--preview` report these findings and exit 0; `--dry-run` and conversion exit 1 when no workbook can be produced.
93
+
94
+ ## Inspection modes
95
+
96
+ The following modes never create a workbook, temporary workbook, or output directory. They are safe to run against an existing destination.
97
+
98
+ ```bash
99
+ jxcel data.json --list
100
+ jxcel data.json --preview
101
+ jxcel data.json --preview --preview-rows 10
102
+ jxcel data.json --dry-run
103
+ jxcel data.json --preview --dry-run
104
+ ```
105
+
106
+ - `--list` builds schemas, reports dataset pointers, record counts, available columns, effective columns after mappings, non-exportable reasons, and unsupported structures. It performs schema-only validation and does not scan cell values for exportability.
107
+ - `--preview` displays bounded records, respecting dataset and column selection. It prepares only the displayed rows and does not export-validate values outside the preview window. `--preview-rows` defaults to 5 and must be a positive integer.
108
+ - `--dry-run` performs full export validation and shows the selected datasets, effective columns, destination, warnings, and unsupported structures. It validates the destination read-only, so an existing file without `--overwrite` or a missing parent directory fails with exit status 1.
109
+ - `--preview --dry-run` combines both: the full export plan is built once and preview rows come from its validated snapshot.
110
+
111
+ `--list` cannot be combined with `--preview` or `--dry-run`. `--preview-rows` requires `--preview`. `--output` and `--overwrite` are rejected with `--list` or preview-only mode because they have no effect there; they are valid with `--dry-run` and normal conversion.
112
+
113
+ ## Dataset and column selection
114
+
115
+ `--dataset` is repeatable and takes a canonical JSON Pointer:
116
+
117
+ ```bash
118
+ jxcel data.json --dataset /students
119
+ jxcel data.json --dataset /students --dataset /orders
120
+ ```
121
+
122
+ Pointer tokens use JSON Pointer escaping: `~` is written as `~0` and `/` as `~1`. For example, a dataset under the key `a/b~c` has the pointer `/a~1b~0c`.
123
+
124
+ Unsupported structures remain visible even when only some datasets are selected. Scalar values and empty objects outside dataset boundaries are listed with their JSON Pointers, so input content that is not exported is visible.
125
+
126
+ `--column-map` and `--exclude-map` are repeatable and take a JSON array of exactly two strings: the dataset pointer and the exact planned column name. Use shell quoting appropriate to your platform.
127
+
128
+ Bash:
129
+
130
+ ```bash
131
+ jxcel data.json \
132
+ --column-map '["/students","user.name"]' \
133
+ --column-map '["/orders","order,id"]' \
134
+ --exclude-map '["/orders","internal=status"]'
135
+ ```
136
+
137
+ PowerShell (verified on Windows in Phase 8):
138
+
139
+ ```powershell
140
+ jxcel data.json `
141
+ --column-map '["/students","user.name"]' `
142
+ --exclude-map '["/orders","internal=status"]'
143
+ ```
144
+
145
+ Mappings are validated against every discovered dataset, but applied only to selected datasets. Include mappings select columns; exclude mappings remove columns afterward and take precedence. In `--dry-run`, a mapping for a valid but unselected dataset is reported as validated but unapplied. Unknown pointers and columns fail clearly.
146
+
147
+ ## Nested values and flattening
148
+
149
+ Nested objects flatten by default. For example, `user.name` becomes a column named `user.name`. An empty nested object outside an array contributes no column in this mode and produces an `empty_object_omitted` warning with its column path and sample record indexes. Use `--no-flatten` for one column per top-level property:
150
+
151
+ ```bash
152
+ jxcel data.json --no-flatten
153
+ ```
154
+
155
+ With `--no-flatten`, nested objects, arrays, and empty objects are written as compact JSON text (`{}` for an empty object, `[]` for an empty array); an empty object no longer produces an `empty_object_omitted` warning. Arrays never expand into rows or worksheets in either mode, and empty objects inside arrays are preserved as JSON text. Flattened column names use a reversible encoding of the original key path; conflicting flattened names fail rather than overwriting data. With `--no-flatten`, top-level keys are used as column names unchanged.
156
+
157
+ ## Output and exit status
158
+
159
+ - `stdout`: listings, previews, dry-run plans, warnings, unsupported findings, and the successful conversion summary.
160
+ - `stderr`: errors and argument-parser diagnostics.
161
+ - If the console cannot encode a character, jxcel escapes it; a closed output pipe exits with status 1 without a traceback.
162
+ - Exit `0`: successful help, version, listing, preview, dry-run, or conversion.
163
+ - Exit `1`: input, JSON, planning, mapping, destination, workbook, or publication failure.
164
+ - Exit `2`: command-line argument or usage error.
165
+
166
+ `--quiet` suppresses only the routine successful conversion summary. Errors, warnings, unsupported findings, and non-exportable dataset notices remain visible. `--quiet` and `--verbose` are mutually exclusive. `--verbose` adds context such as the input path and worksheet assignments.
167
+
168
+ `--list` and `--preview` treat the absence of an exportable dataset as informational and exit 0 after reporting it. `--dry-run` and normal conversion exit 1 because no workbook can be produced.
169
+
170
+ ## Data preservation
171
+
172
+ - Strings remain strings; numeric-looking and date-like text is not reinterpreted.
173
+ - Direct integer values with absolute value at least `10**15` are written as text with an `integer_precision_as_text` warning; smaller direct integers remain numeric.
174
+ - Direct float values remain numeric and are never rounded; values with more than 15 significant decimal digits produce a `float_precision_limited` warning, and direct finite floats outside Excel's numeric range fail export validation.
175
+ - Values written as JSON text (arrays in either mode, and nested objects under `--no-flatten`) produce a `nested_value_as_json_text` warning; numbers inside that text are not converted or range-checked individually.
176
+ - Export validation enforces Excel's limits: at most 1,048,575 data rows per dataset (the header uses row 1 of Excel's 1,048,576 rows), at most 16,384 columns, and at most 32,767 UTF-16 code units per cell or column header. Cell text and column headers reject control characters below `U+0020` other than tab, line feed, and carriage return, lone surrogates, and `U+FFFE`/`U+FFFF`; control characters inside JSON-serialized nested values are escaped. These failures are reported rather than truncated.
177
+ - Formula-like strings are written as text, never as formulas.
178
+ - Null and missing values become blank cells.
179
+
180
+ Warnings are aggregated by code, dataset, and effective column, with an occurrence count and at most five sample record indexes.
181
+
182
+ ## Workbook output
183
+
184
+ Each selected exportable dataset becomes one worksheet, in plan order. Worksheet names are derived from dataset pointers: the root dataset is `root`, and pointer tokens are joined with dots. Names are sanitized for Excel, truncated to 31 UTF-16 code units, and made unique case-insensitively with `_2`, `_3`, and so on. The name `History` is reserved case-insensitively.
185
+
186
+ The header row is bold, filled, and vertically centered, with the header row frozen and an auto-filter over the data range. Column widths are based on the header and the first 100 data rows, with padding, and are clamped to 10–60 characters.
187
+
188
+ The workbook is written and validated through one open temporary-file stream before publication. On POSIX, the temporary file is mode `0600` while it is written and validated; its intended final mode is applied only after validation. With `--overwrite`, an existing regular file's POSIX permission bits are preserved; new files use the platform's normal file-creation mode. A permission failure before publication leaves the existing destination unchanged. Windows temporary files inherit the output directory's ACL; Windows `chmod` does not preserve general ACLs.
189
+
190
+ Choose an output directory whose access controls are appropriate for the workbook data. jxcel protects against accidental concurrent publishers: no-overwrite publication uses a same-directory hard link, and overwrite uses the operating system's replace operation. It does not defend against a malicious process running as the same user or another user/process with permission to change entries in the output directory. The temporary pathname is still used for publication and cleanup, so a hostile writable output directory is outside the security guarantee.
191
+
192
+ ## Platform validation
193
+
194
+ The current 12-combination matrix passed in [GitHub Actions run 41933979297](https://github.com/AbuTaha7000D/jxcel/actions/runs/41933979297), validating commit `6d2e5e3f3f0b9cb4a0b7985847a496be744cc1e7`.
195
+
196
+ | Platform | Status | Evidence |
197
+ |---|---|---|
198
+ | Linux (`ubuntu-24.04`, plus local Fedora 44) | **PASS on Python 3.11–3.14** | All four jobs passed all 309 unit tests and 25 acceptance checks. Each built and inspected wheel/sdist, installed each in isolated environments, ran CLI/pipx smoke checks, and verified publication behavior. |
199
+ | Windows (`windows-2025`, X64) | **PASS on Python 3.11–3.14** | All four jobs passed the 309-test suite (306 passed, three POSIX-only permission-bit tests skipped) and 25 acceptance checks. Windows shell quoting and native console checks passed. |
200
+ | macOS (`macos-15`, ARM64) | **PASS on Python 3.11–3.14** | All four jobs passed all 309 unit tests and 25 acceptance checks. POSIX permission preservation and hard-link publication checks passed. |
201
+
202
+ Reproducible Linux install and smoke commands, with temporary directories:
203
+
204
+ ```bash
205
+ python -m venv /tmp/jxcel-venv
206
+ /tmp/jxcel-venv/bin/python -m pip install .
207
+ cd /tmp
208
+ /tmp/jxcel-venv/bin/jxcel --version
209
+ /tmp/jxcel-venv/bin/jxcel --help
210
+ ```
211
+
212
+ The Linux, Windows, and macOS Python matrix is automated by `.github/workflows/phase8-cross-platform.yml`, which is dispatched manually. The current verification run is linked above.
213
+
214
+ The full test suite uses the standard library. Bash:
215
+
216
+ ```bash
217
+ PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python -m unittest discover -s tests
218
+ ```
219
+
220
+ PowerShell:
221
+
222
+ ```powershell
223
+ $env:PYTHONDONTWRITEBYTECODE = "1"
224
+ $env:PYTHONPATH = "src"
225
+ python -m unittest discover -s tests
226
+ ```
227
+
228
+ Windows CMD:
229
+
230
+ ```bat
231
+ set PYTHONDONTWRITEBYTECODE=1
232
+ set PYTHONPATH=src
233
+ python -m unittest discover -s tests
234
+ ```
235
+
236
+ ## GitHub and PyPI release process
237
+
238
+ Create each GitHub Release from a version tag (for example, `v0.1.0`) pointing to the reviewed release commit on `main`. GitHub provides source archives for the tag. Creating a GitHub Release does not publish a Python package to PyPI.
239
+
240
+ The manually dispatched [PyPI workflow](.github/workflows/publish.yml) builds a wheel and source distribution. Its `publish` input defaults to `false`; the publishing job is eligible only when the workflow is dispatched with `publish=true` from a tag whose name begins with `v`. The tag must identify the reviewed release commit. Do not enable that input without separate authorization to publish this release.
241
+
242
+ The workflow uses [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/) and does not store a PyPI token. Before first publication, configure the PyPI trusted publisher for owner `AbuTaha7000D`, repository `jxcel`, workflow `.github/workflows/publish.yml`, and GitHub environment `pypi`. Configure that GitHub environment with the required release reviewers. The project currently has no PyPI registration; PyPI's [trusted publisher project creation](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/) flow can register it during an explicitly authorized first publish.
243
+
244
+ ## Limitations
245
+
246
+ - The complete JSON document and the export snapshot are held in memory; jxcel is not a streaming converter.
247
+ - JSON documents nested more than 500 object/array levels are rejected with a path-aware error. This fixed limit avoids interpreter-dependent parser behavior and excessive discovery paths; brackets inside strings do not count.
248
+ - Concurrent mutation of source records while a plan is being built is unsupported. Constructing or forging internal plan objects directly can bypass validation and is outside the supported contract.
249
+ - The matrix covers GitHub-hosted Ubuntu 24.04, Windows 2025, and macOS 15; other OS releases, hardware architectures, and filesystems were not tested.
250
+ - Hard-link publication depends on filesystem support and was exercised on Linux `tmpfs` and the Windows and macOS runner temporary filesystems; other filesystem types were not tested.
251
+ - The current matrix ran Python 3.11–3.14 on all three named operating systems; future interpreter patch releases and OS runner images may differ.
252
+ - The detailed roadmap is maintained locally and is not included in Git or package distributions.
253
+
254
+ ## License
255
+
256
+ jxcel is licensed under the MIT License. See [LICENSE](LICENSE) for the full text.
257
+
258
+ ## Project guidance
259
+
260
+ - [AGENTS.md](AGENTS.md) contains repository-wide instructions for coding agents.
261
+ - The detailed product roadmap is maintained locally and may not be present in a checkout.
262
+
263
+ The former `export_students.py` legacy exporter was removed during project cleanup. It is not part of jxcel or its distributions.
jxcel-0.1.0/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # jxcel
2
+
3
+ `jxcel` is a cross-platform command-line application for converting JSON files into formatted Excel `.xlsx` workbooks. It discovers tabular object arrays in general JSON documents; it has no fixed columns or domain-specific assumptions.
4
+
5
+ ## Development status
6
+
7
+ The converter is functional. JSON loading and validation, dataset discovery, schema planning and value preparation, workbook generation with validated publication, and command-line integration are implemented in `src/jxcel/`. The package has not been published.
8
+
9
+ Current cross-platform release verification passed in GitHub Actions run [41933979297](https://github.com/AbuTaha7000D/jxcel/actions/runs/41933979297) on commit `6d2e5e3f3f0b9cb4a0b7985847a496be744cc1e7`. All 12 Linux, Windows, and macOS × Python 3.11–3.14 jobs passed. Each ran the full 309-test suite and 25 CLI acceptance checks; Windows skipped three POSIX-only permission tests. The workflow also built and inspected wheel and source distributions, installed them in separate environments, and verified pipx installation.
10
+
11
+ The earlier Phase 8 run [41666703215](https://github.com/AbuTaha7000D/jxcel/actions/runs/41666703215) validated commit `f351669e6ed5ef072eb888e9a2f2f85401832210` on Windows and macOS with the original 299-test suite.
12
+
13
+ Release notes for version `0.1.0` are in [RELEASE_NOTES.md](https://github.com/AbuTaha7000D/jxcel/blob/main/RELEASE_NOTES.md).
14
+
15
+ ## Requirements
16
+
17
+ - Python 3.11 or newer is declared. Python 3.11, 3.12, 3.13, and 3.14 have all been exercised on Ubuntu 24.04, Windows 2025, and macOS 15 in run 41933979297.
18
+ - Runtime dependencies: the Python standard library and `openpyxl`.
19
+ - Linux, Windows, and macOS are intended targets. All three have been exercised: Linux locally, and Windows and macOS on GitHub-hosted runners in Phase 8.
20
+
21
+ ## Installation
22
+
23
+ A package distribution is not published yet. From a local checkout:
24
+
25
+ ```bash
26
+ python -m pip install .
27
+ ```
28
+
29
+ This command was verified on Linux in an isolated virtual environment and on the Windows and macOS CI runners in Phase 8. The build uses isolation, so it needs access to a package index or a populated build-dependency cache; an offline install fails if the required `setuptools` build dependency is unavailable.
30
+
31
+ An isolated installation from the checkout was also verified with `pipx`: 1.18.11 on Linux and 1.18.12 on the Windows and macOS CI runners.
32
+
33
+ ```bash
34
+ pipx install .
35
+ ```
36
+
37
+ Both commands install a `jxcel` command that points at `jxcel.cli:main`. Command availability, the isolated `pipx` command path, and execution from outside the checkout were verified on Linux, Windows, and macOS.
38
+
39
+ ## Usage
40
+
41
+ Exactly one input source is required: positional `INPUT` or `-i/--input PATH`.
42
+
43
+ ```bash
44
+ jxcel data.json
45
+ jxcel -i data.json
46
+ jxcel /path/to/data.json
47
+ jxcel -i /path/to/data.json -o result.xlsx
48
+ ```
49
+
50
+ By default, the output is written beside the input with an `.xlsx` suffix, so `data.json` produces `data.xlsx`. The output parent directory must already exist; jxcel never creates directories.
51
+
52
+ Existing output files are preserved unless `--overwrite` is supplied:
53
+
54
+ ```bash
55
+ jxcel data.json --overwrite
56
+ ```
57
+
58
+ Without `--overwrite`, an existing destination is an error. With it, jxcel builds and validates a temporary workbook first, then replaces the destination through the approved publication path. jxcel does not claim crash durability or stronger atomicity than the operating system and filesystem provide.
59
+
60
+ No-overwrite publication creates the destination with a same-directory hard link, so the temporary and destination files stay on one filesystem. Some filesystems do not support hard links, including FAT32/exFAT and some network or container mounts. On such filesystems, no-overwrite publication fails with exit status 1 and an explicit error. jxcel does not fall back to rename or replace, because that fallback could destroy a destination created concurrently. Overwrite publication uses the operating system's replace operation and depends on that filesystem's support. Hard-link behavior was exercised on Linux `tmpfs` and on the Windows and macOS runner temporary filesystems; other filesystem types, including FAT32/exFAT and network mounts, were not tested.
61
+
62
+ ## Input validation
63
+
64
+ jxcel reads the input as UTF-8 and accepts an optional UTF-8 BOM. Empty or whitespace-only files, malformed JSON, invalid UTF-8, and trailing content after the JSON value are rejected with exit status 1 and a path-aware error. Malformed JSON reports the line and column; invalid UTF-8 reports the byte offset.
65
+
66
+ Object keys must be unique at every level. Duplicate keys are rejected even when one is written with an escape such as `\u0061`, because it decodes to the same key; the same key in separate objects is allowed. `NaN`, `Infinity`, and `-Infinity` are rejected as non-standard JSON constants. JSON real numbers must be finite: tokens that overflow a Python float or underflow a nonzero value to zero are rejected. Integers decode as Python integers, subject to Python's configured integer-string conversion limit.
67
+
68
+ The loader does not restrict the JSON root category: objects, arrays, strings, numbers, booleans, and `null` are all accepted, subject to the validation above. Dataset discovery then treats a root that is not an object or array as `unsupported_root`. Discovery reports an empty array outside dataset records as `empty_array`, and an empty object outside arrays as `empty_object`; neither is an exportable dataset. `--list` and `--preview` report these findings and exit 0; `--dry-run` and conversion exit 1 when no workbook can be produced.
69
+
70
+ ## Inspection modes
71
+
72
+ The following modes never create a workbook, temporary workbook, or output directory. They are safe to run against an existing destination.
73
+
74
+ ```bash
75
+ jxcel data.json --list
76
+ jxcel data.json --preview
77
+ jxcel data.json --preview --preview-rows 10
78
+ jxcel data.json --dry-run
79
+ jxcel data.json --preview --dry-run
80
+ ```
81
+
82
+ - `--list` builds schemas, reports dataset pointers, record counts, available columns, effective columns after mappings, non-exportable reasons, and unsupported structures. It performs schema-only validation and does not scan cell values for exportability.
83
+ - `--preview` displays bounded records, respecting dataset and column selection. It prepares only the displayed rows and does not export-validate values outside the preview window. `--preview-rows` defaults to 5 and must be a positive integer.
84
+ - `--dry-run` performs full export validation and shows the selected datasets, effective columns, destination, warnings, and unsupported structures. It validates the destination read-only, so an existing file without `--overwrite` or a missing parent directory fails with exit status 1.
85
+ - `--preview --dry-run` combines both: the full export plan is built once and preview rows come from its validated snapshot.
86
+
87
+ `--list` cannot be combined with `--preview` or `--dry-run`. `--preview-rows` requires `--preview`. `--output` and `--overwrite` are rejected with `--list` or preview-only mode because they have no effect there; they are valid with `--dry-run` and normal conversion.
88
+
89
+ ## Dataset and column selection
90
+
91
+ `--dataset` is repeatable and takes a canonical JSON Pointer:
92
+
93
+ ```bash
94
+ jxcel data.json --dataset /students
95
+ jxcel data.json --dataset /students --dataset /orders
96
+ ```
97
+
98
+ Pointer tokens use JSON Pointer escaping: `~` is written as `~0` and `/` as `~1`. For example, a dataset under the key `a/b~c` has the pointer `/a~1b~0c`.
99
+
100
+ Unsupported structures remain visible even when only some datasets are selected. Scalar values and empty objects outside dataset boundaries are listed with their JSON Pointers, so input content that is not exported is visible.
101
+
102
+ `--column-map` and `--exclude-map` are repeatable and take a JSON array of exactly two strings: the dataset pointer and the exact planned column name. Use shell quoting appropriate to your platform.
103
+
104
+ Bash:
105
+
106
+ ```bash
107
+ jxcel data.json \
108
+ --column-map '["/students","user.name"]' \
109
+ --column-map '["/orders","order,id"]' \
110
+ --exclude-map '["/orders","internal=status"]'
111
+ ```
112
+
113
+ PowerShell (verified on Windows in Phase 8):
114
+
115
+ ```powershell
116
+ jxcel data.json `
117
+ --column-map '["/students","user.name"]' `
118
+ --exclude-map '["/orders","internal=status"]'
119
+ ```
120
+
121
+ Mappings are validated against every discovered dataset, but applied only to selected datasets. Include mappings select columns; exclude mappings remove columns afterward and take precedence. In `--dry-run`, a mapping for a valid but unselected dataset is reported as validated but unapplied. Unknown pointers and columns fail clearly.
122
+
123
+ ## Nested values and flattening
124
+
125
+ Nested objects flatten by default. For example, `user.name` becomes a column named `user.name`. An empty nested object outside an array contributes no column in this mode and produces an `empty_object_omitted` warning with its column path and sample record indexes. Use `--no-flatten` for one column per top-level property:
126
+
127
+ ```bash
128
+ jxcel data.json --no-flatten
129
+ ```
130
+
131
+ With `--no-flatten`, nested objects, arrays, and empty objects are written as compact JSON text (`{}` for an empty object, `[]` for an empty array); an empty object no longer produces an `empty_object_omitted` warning. Arrays never expand into rows or worksheets in either mode, and empty objects inside arrays are preserved as JSON text. Flattened column names use a reversible encoding of the original key path; conflicting flattened names fail rather than overwriting data. With `--no-flatten`, top-level keys are used as column names unchanged.
132
+
133
+ ## Output and exit status
134
+
135
+ - `stdout`: listings, previews, dry-run plans, warnings, unsupported findings, and the successful conversion summary.
136
+ - `stderr`: errors and argument-parser diagnostics.
137
+ - If the console cannot encode a character, jxcel escapes it; a closed output pipe exits with status 1 without a traceback.
138
+ - Exit `0`: successful help, version, listing, preview, dry-run, or conversion.
139
+ - Exit `1`: input, JSON, planning, mapping, destination, workbook, or publication failure.
140
+ - Exit `2`: command-line argument or usage error.
141
+
142
+ `--quiet` suppresses only the routine successful conversion summary. Errors, warnings, unsupported findings, and non-exportable dataset notices remain visible. `--quiet` and `--verbose` are mutually exclusive. `--verbose` adds context such as the input path and worksheet assignments.
143
+
144
+ `--list` and `--preview` treat the absence of an exportable dataset as informational and exit 0 after reporting it. `--dry-run` and normal conversion exit 1 because no workbook can be produced.
145
+
146
+ ## Data preservation
147
+
148
+ - Strings remain strings; numeric-looking and date-like text is not reinterpreted.
149
+ - Direct integer values with absolute value at least `10**15` are written as text with an `integer_precision_as_text` warning; smaller direct integers remain numeric.
150
+ - Direct float values remain numeric and are never rounded; values with more than 15 significant decimal digits produce a `float_precision_limited` warning, and direct finite floats outside Excel's numeric range fail export validation.
151
+ - Values written as JSON text (arrays in either mode, and nested objects under `--no-flatten`) produce a `nested_value_as_json_text` warning; numbers inside that text are not converted or range-checked individually.
152
+ - Export validation enforces Excel's limits: at most 1,048,575 data rows per dataset (the header uses row 1 of Excel's 1,048,576 rows), at most 16,384 columns, and at most 32,767 UTF-16 code units per cell or column header. Cell text and column headers reject control characters below `U+0020` other than tab, line feed, and carriage return, lone surrogates, and `U+FFFE`/`U+FFFF`; control characters inside JSON-serialized nested values are escaped. These failures are reported rather than truncated.
153
+ - Formula-like strings are written as text, never as formulas.
154
+ - Null and missing values become blank cells.
155
+
156
+ Warnings are aggregated by code, dataset, and effective column, with an occurrence count and at most five sample record indexes.
157
+
158
+ ## Workbook output
159
+
160
+ Each selected exportable dataset becomes one worksheet, in plan order. Worksheet names are derived from dataset pointers: the root dataset is `root`, and pointer tokens are joined with dots. Names are sanitized for Excel, truncated to 31 UTF-16 code units, and made unique case-insensitively with `_2`, `_3`, and so on. The name `History` is reserved case-insensitively.
161
+
162
+ The header row is bold, filled, and vertically centered, with the header row frozen and an auto-filter over the data range. Column widths are based on the header and the first 100 data rows, with padding, and are clamped to 10–60 characters.
163
+
164
+ The workbook is written and validated through one open temporary-file stream before publication. On POSIX, the temporary file is mode `0600` while it is written and validated; its intended final mode is applied only after validation. With `--overwrite`, an existing regular file's POSIX permission bits are preserved; new files use the platform's normal file-creation mode. A permission failure before publication leaves the existing destination unchanged. Windows temporary files inherit the output directory's ACL; Windows `chmod` does not preserve general ACLs.
165
+
166
+ Choose an output directory whose access controls are appropriate for the workbook data. jxcel protects against accidental concurrent publishers: no-overwrite publication uses a same-directory hard link, and overwrite uses the operating system's replace operation. It does not defend against a malicious process running as the same user or another user/process with permission to change entries in the output directory. The temporary pathname is still used for publication and cleanup, so a hostile writable output directory is outside the security guarantee.
167
+
168
+ ## Platform validation
169
+
170
+ The current 12-combination matrix passed in [GitHub Actions run 41933979297](https://github.com/AbuTaha7000D/jxcel/actions/runs/41933979297), validating commit `6d2e5e3f3f0b9cb4a0b7985847a496be744cc1e7`.
171
+
172
+ | Platform | Status | Evidence |
173
+ |---|---|---|
174
+ | Linux (`ubuntu-24.04`, plus local Fedora 44) | **PASS on Python 3.11–3.14** | All four jobs passed all 309 unit tests and 25 acceptance checks. Each built and inspected wheel/sdist, installed each in isolated environments, ran CLI/pipx smoke checks, and verified publication behavior. |
175
+ | Windows (`windows-2025`, X64) | **PASS on Python 3.11–3.14** | All four jobs passed the 309-test suite (306 passed, three POSIX-only permission-bit tests skipped) and 25 acceptance checks. Windows shell quoting and native console checks passed. |
176
+ | macOS (`macos-15`, ARM64) | **PASS on Python 3.11–3.14** | All four jobs passed all 309 unit tests and 25 acceptance checks. POSIX permission preservation and hard-link publication checks passed. |
177
+
178
+ Reproducible Linux install and smoke commands, with temporary directories:
179
+
180
+ ```bash
181
+ python -m venv /tmp/jxcel-venv
182
+ /tmp/jxcel-venv/bin/python -m pip install .
183
+ cd /tmp
184
+ /tmp/jxcel-venv/bin/jxcel --version
185
+ /tmp/jxcel-venv/bin/jxcel --help
186
+ ```
187
+
188
+ The Linux, Windows, and macOS Python matrix is automated by `.github/workflows/phase8-cross-platform.yml`, which is dispatched manually. The current verification run is linked above.
189
+
190
+ The full test suite uses the standard library. Bash:
191
+
192
+ ```bash
193
+ PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python -m unittest discover -s tests
194
+ ```
195
+
196
+ PowerShell:
197
+
198
+ ```powershell
199
+ $env:PYTHONDONTWRITEBYTECODE = "1"
200
+ $env:PYTHONPATH = "src"
201
+ python -m unittest discover -s tests
202
+ ```
203
+
204
+ Windows CMD:
205
+
206
+ ```bat
207
+ set PYTHONDONTWRITEBYTECODE=1
208
+ set PYTHONPATH=src
209
+ python -m unittest discover -s tests
210
+ ```
211
+
212
+ ## GitHub and PyPI release process
213
+
214
+ Create each GitHub Release from a version tag (for example, `v0.1.0`) pointing to the reviewed release commit on `main`. GitHub provides source archives for the tag. Creating a GitHub Release does not publish a Python package to PyPI.
215
+
216
+ The manually dispatched [PyPI workflow](.github/workflows/publish.yml) builds a wheel and source distribution. Its `publish` input defaults to `false`; the publishing job is eligible only when the workflow is dispatched with `publish=true` from a tag whose name begins with `v`. The tag must identify the reviewed release commit. Do not enable that input without separate authorization to publish this release.
217
+
218
+ The workflow uses [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/) and does not store a PyPI token. Before first publication, configure the PyPI trusted publisher for owner `AbuTaha7000D`, repository `jxcel`, workflow `.github/workflows/publish.yml`, and GitHub environment `pypi`. Configure that GitHub environment with the required release reviewers. The project currently has no PyPI registration; PyPI's [trusted publisher project creation](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/) flow can register it during an explicitly authorized first publish.
219
+
220
+ ## Limitations
221
+
222
+ - The complete JSON document and the export snapshot are held in memory; jxcel is not a streaming converter.
223
+ - JSON documents nested more than 500 object/array levels are rejected with a path-aware error. This fixed limit avoids interpreter-dependent parser behavior and excessive discovery paths; brackets inside strings do not count.
224
+ - Concurrent mutation of source records while a plan is being built is unsupported. Constructing or forging internal plan objects directly can bypass validation and is outside the supported contract.
225
+ - The matrix covers GitHub-hosted Ubuntu 24.04, Windows 2025, and macOS 15; other OS releases, hardware architectures, and filesystems were not tested.
226
+ - Hard-link publication depends on filesystem support and was exercised on Linux `tmpfs` and the Windows and macOS runner temporary filesystems; other filesystem types were not tested.
227
+ - The current matrix ran Python 3.11–3.14 on all three named operating systems; future interpreter patch releases and OS runner images may differ.
228
+ - The detailed roadmap is maintained locally and is not included in Git or package distributions.
229
+
230
+ ## License
231
+
232
+ jxcel is licensed under the MIT License. See [LICENSE](LICENSE) for the full text.
233
+
234
+ ## Project guidance
235
+
236
+ - [AGENTS.md](AGENTS.md) contains repository-wide instructions for coding agents.
237
+ - The detailed product roadmap is maintained locally and may not be present in a checkout.
238
+
239
+ The former `export_students.py` legacy exporter was removed during project cleanup. It is not part of jxcel or its distributions.
@@ -0,0 +1,61 @@
1
+ # jxcel 0.1.0 Release Notes
2
+
3
+ Version: `0.1.0`
4
+
5
+ Status: **initial release**. This version has not been published as a package distribution to PyPI or any other package index.
6
+
7
+ ## Summary
8
+
9
+ `jxcel` is a cross-platform command-line application for converting JSON files into formatted Excel `.xlsx` workbooks. It discovers tabular object arrays in general JSON documents and has no fixed columns or domain-specific assumptions.
10
+
11
+ This release includes:
12
+
13
+ - Strict JSON loading with path-aware errors for malformed JSON, invalid UTF-8, duplicate object keys, non-standard numeric constants, unsupported float ranges, and integer conversion limits. Documents deeper than 500 object/array levels are rejected consistently across supported interpreters.
14
+ - Deterministic dataset discovery, including reporting of unsupported structures and non-exportable datasets.
15
+ - Schema planning with nested-object flattening (or `--no-flatten`), column selection, and reversible column-name encoding.
16
+ - Dataset and column selection with repeatable `--dataset`, `--column-map`, and `--exclude-map` options.
17
+ - Inspection modes: `--list`, `--preview` with `--preview-rows`, and `--dry-run`, including `--preview --dry-run`.
18
+ - Data-preserving value handling with aggregated warnings and enforcement of Excel row, column, and cell-text limits.
19
+ - Workbook generation with worksheet naming, header formatting, frozen headers, auto-filters, and column widths.
20
+ - Validated publication through one retained temporary-file stream: POSIX temporary workbooks remain mode `0600` during serialization and validation; no-overwrite publication uses a same-directory hard link; `--overwrite` uses the operating system's replace operation.
21
+ - User-facing output through `stdout` and errors through `stderr`, with exit statuses `0` (success), `1` (processing or publication failure), and `2` (usage error).
22
+
23
+ ## Installation
24
+
25
+ No distribution is published. Install from a local checkout:
26
+
27
+ ```bash
28
+ python -m pip install .
29
+ ```
30
+
31
+ Or install in an isolated environment with `pipx`:
32
+
33
+ ```bash
34
+ pipx install .
35
+ ```
36
+
37
+ Both commands install a `jxcel` command that points at `jxcel.cli:main`. The build uses isolation, so it needs access to a package index or a populated build-dependency cache.
38
+
39
+ ## Validation evidence
40
+
41
+ - The 309-test `unittest` suite passed on all 12 supported OS/Python combinations in [GitHub Actions run 41933979297](https://github.com/AbuTaha7000D/jxcel/actions/runs/41933979297), commit `6d2e5e3f3f0b9cb4a0b7985847a496be744cc1e7`. Windows skipped three POSIX-only permission tests per job.
42
+ - Linux, Windows, and macOS each passed 25 CLI acceptance checks on Python 3.11, 3.12, 3.13, and 3.14.
43
+ - The matrix built and inspected the wheel and source distribution, installed each into isolated environments, and verified pipx installation and CLI conversion.
44
+
45
+ ## Known limitations
46
+
47
+ - The complete JSON document and the export snapshot are held in memory; jxcel is not a streaming converter.
48
+ - No-overwrite publication relies on hard links, so it depends on filesystem support. Filesystems without hard-link support fail with an explicit error rather than falling back.
49
+ - Windows/macOS and Python 3.11–3.14 compatibility was verified on the named GitHub-hosted runner images in run 41933979297; other operating-system releases, architectures, and filesystems were not tested.
50
+ - There is no graphical user interface; jxcel is a command-line tool only.
51
+ - The package is not published, so there is no supported installation from a package index.
52
+ - Workbook contents were validated by reopening the generated file with openpyxl; opening the workbook in Excel or LibreOffice was not verified.
53
+ - No crash-durability guarantee stronger than the operating system and filesystem provide is claimed.
54
+
55
+ ## License
56
+
57
+ jxcel is licensed under the MIT License. See [LICENSE](LICENSE).
58
+
59
+ ## Legacy script
60
+
61
+ The former `export_students.py` legacy exporter was removed during project cleanup. It is not part of jxcel or its distributions.
@@ -0,0 +1,43 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77.0.3"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "jxcel"
7
+ version = "0.1.0"
8
+ description = "A cross-platform CLI for converting JSON datasets into Excel workbooks"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ {name = "Mahmoud Ehab"},
15
+ ]
16
+ keywords = ["json", "excel", "xlsx", "cli", "converter"]
17
+ dependencies = ["openpyxl>=3.1.5,<4"]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Environment :: Console",
21
+ "Intended Audience :: End Users/Desktop",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Programming Language :: Python :: 3.13",
27
+ "Programming Language :: Python :: 3.14",
28
+ "Topic :: Utilities",
29
+ ]
30
+
31
+ [project.urls]
32
+ "Source" = "https://github.com/abutaha7000d/jxcel"
33
+
34
+ [project.scripts]
35
+ jxcel = "jxcel.cli:main"
36
+
37
+ [tool.setuptools]
38
+ package-dir = {"" = "src"}
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+ include = ["jxcel", "jxcel.*"]
43
+ namespaces = false