Reorganize examples into three tiers; promote ListLayout into the library - #55
Merged
Conversation
Three-tier examples taxonomy (tutorial snippets / useful tools / advanced) with acceptance criteria, promoting list layout into the library, extracting the EventKit reminders example to its own repo, and adding CI.
…plates Examples and snippets can now read templates checked into the repo instead of depending on Application Support state that does not exist on a fresh clone.
Promotes layout logic that was duplicated across two examples into the library, where it is unit-tested for the first time and reusable by outside consumers.
Layout now comes from LabelKit's ListLayout; the tool keeps only stdin parsing. Drops the example- prefix since Tier 2 tools are meant to be installed.
Compiled on every build, so a tutorial referencing a renamed API breaks CI.
example-label's template and preview behavior moved to snippets; its dual-renderer behavior becomes a debugging tool for renderer disagreements.
…ions
- Give each renderer its own error boundary so one failing (e.g. Labelary
unreachable offline) does not stop the other from running; report the
failure and continue instead of propagating.
- Report each rendered PNG's pixel dimensions and byte size alongside the
inline preview, parsed from the IHDR chunk without an image framework
dependency — this is the actual diagnostic signal when the two renderers
disagree, per the project spec ("shows both inline and reports
dimensions").
Reminders.swift has no home in a companion `reminders` repo yet, so example-reminderlist and Examples/ReminderList/ are NOT removed in this commit (deferred until that repo exists and builds) - this only covers the doc-cleanup portion of the examples reorganization. - LabelKit.md: StencilProcessor/LengthInjector never existed; replaced with the real processor names ResolveTemplates/InjectLength, added ListLayout to Other Types, and fixed a stale `example-label` shell snippet. - README.md: rewrote the Examples section into the three real tiers (Snippets/ tutorials, labelprint, Advanced/), fixed the printer-host override examples and the StencilTemplateStore consumer reference - all previously pointed at example-label/example-listlabel, which no longer exist. - AGENTS.md: updated the Commands block to match. KeyValueContext investigation (Apps/LabelGUI/LabelGUI/KeyValueContext.swift vs Sources/LabelKit/Processors/KeyValueContext.swift): not a fork despite the shared filename. The LabelGUI file imports LabelKit and defines only KeyValueTableView, a SwiftUI view consuming LabelKit's KeyValueContext/ KeyValueRow types directly - it re-declares neither. Classification of its full 164 lines: (a) GUI-specific, stays in LabelGUI - all of it. (b) generally useful, promote to LabelKit - none. (c) redundant, delete - none. No library API change made or warranted. swift build && swift test: Build complete!, 105 tests / 25 suites passed. swift package describe confirms products labelprint, compare-renderers, batch-badges, example-reminderlist - no example-label, no example-listlabel.
…dge cases) - labelprint: split on any newline (not just \n) so CRLF/lone-CR input parses correctly instead of collapsing into one corrupted item; trim with .whitespacesAndNewlines to keep stray CR out of ^FD content - ListLayout: printWidthDots now derives from the environment's RenderGeometry when unset, instead of a hardcoded 1200 that silently disagreed with non-4x stocks like label2x1 - compare-renderers: pngDimensions verifies the PNG signature before reading IHDR offsets, instead of returning confident nonsense for non-PNG input - batch-badges: CSV rows with the wrong field count now raise a ValidationError naming the row and expected/actual counts, instead of silently zipping to an empty value - README: document LabelGUI explicitly as the Tier 3 GUI example - spec: correct the structure block to name PrintAList.swift, matching the shipped tree, instead of the never-built PrintToNetwork.swift Adds CRLF/lone-CR and printWidthDots coverage to the existing test suites (105 -> 110 tests).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Reorganizes the package's ad-hoc examples into three tiers, and promotes list-layout
logic that was duplicated across two examples into the library.
Implements the design spec
via this plan (both included in this PR).
What changed
Tier 1 — tutorial snippets. New top-level
Snippets/directory, auto-discoveredby SwiftPM with no
Package.swiftentry. Five ~15-line tutorials, each teaching onething, compiled on every build so a tutorial referencing a renamed API breaks CI
instead of quietly misleading a reader.
Tier 2 —
labelprint. Replacesexample-listlabel. Reads lines on stdin andprints them as one long label; keeps only stdin parsing now that layout lives in the
library. Subcommands
print(default),preview,zpl,list. Drops theexample-prefix, since these are meant to be symlinked into~/bin.Tier 3.
compare-renderersrenders the same ZPL through both Labelary andzpl2png to expose renderer disagreements — this is the ZPL-debugging tool.
batch-badgesrenders one Stencil template over a CSV to make N labels. LabelGUI isnow documented as the Tier 3 GUI example.
Library:
ListLayout.generate_labelwas duplicated across two examples andhad never been tested. It is now one public
ListLayouttype inSources/LabelKit/Labels/, with 10 unit tests. This is what unblockst#42 —
tcan consume it ratherthan copying it a third time.
Library:
StencilTemplateStore.init(fileURL:). The store previously resolvedonly to Application Support / group-container paths, so examples depended on
invisible machine state.
example-labelran locally only because LabelGUI had lefta
templates.jsonin a group container; on a fresh clone it threw. Examples nowread seed templates checked into the repo.
CI. The repo had none. This matters beyond hygiene: snippets' entire anti-rot
guarantee is that
swift buildcompiles them, which is only true if something runs it.Docs. The DocC catalog referenced
StencilProcessorandLengthInjector—neither has ever existed. Corrected to
ResolveTemplates/InjectLength.Notable fixes found during review
\r\nas asingle
Character, sosplit(separator: "\n")never split CRLF text — a 5-linelist parsed to one item with raw CR bytes landing inside
^FD. AnyWindows-authored or pasted list hit this. Fixed with tests.
ListLayout.printWidthDotsignored its environment, hardcoding 1200. Itcoincidentally matched 4-inch stock, which is why nothing caught it; on
label2x1the ZPL declared 1200 dots while the geometry said 600, so previews and print
would disagree. Now derived from the environment, with an explicit override.
compare-renderersaborted before the offline renderer if the network one failed,forfeiting its entire offline value. Each renderer is now isolated, and each
reports its PNG dimensions — which is how you see the disagreement.
Deliberately not done
example-reminderlistsurvives. It was to move to a newremindersrepo thatdoes not exist yet; deleting the only copy of
Reminders.swiftwould bedestructive. Docs still describe it. Removing it is follow-up work.
//!and@Snippetrender).^FBwork lands in one libraryplace next to the length estimator instead of in two examples.
Verification
swift buildclean; 110 tests passing (up from 89). Every example was exercisedend-to-end. Nothing was sent to the physical printer at any point.