postsvg 0.1.0 → 0.3.0

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.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +105 -0
  3. data/CLAUDE.md +173 -0
  4. data/Gemfile +2 -3
  5. data/README.adoc +456 -179
  6. data/Rakefile +100 -0
  7. data/TODO.roadmap/00-architecture.md +139 -0
  8. data/TODO.roadmap/01-autoload-migration.md +39 -0
  9. data/TODO.roadmap/02-isolate-dormant-code.md +51 -0
  10. data/TODO.roadmap/03-domain-model.md +66 -0
  11. data/TODO.roadmap/04-lexer.md +40 -0
  12. data/TODO.roadmap/05-parser.md +43 -0
  13. data/TODO.roadmap/06-graphics-state.md +45 -0
  14. data/TODO.roadmap/07-matrix-and-color.md +37 -0
  15. data/TODO.roadmap/08-svg-builder.md +51 -0
  16. data/TODO.roadmap/09-renderer.md +52 -0
  17. data/TODO.roadmap/10-visitor.md +58 -0
  18. data/TODO.roadmap/11-operator-coverage.md +103 -0
  19. data/TODO.roadmap/12-svg-domain.md +62 -0
  20. data/TODO.roadmap/13-translation-handlers.md +69 -0
  21. data/TODO.roadmap/14-ps-serializer.md +49 -0
  22. data/TODO.roadmap/15-cli-and-public-api.md +47 -0
  23. data/TODO.roadmap/16-specs.md +84 -0
  24. data/TODO.roadmap/17-docs-sync.md +47 -0
  25. data/TODO.roadmap/18-performance-and-determinism.md +47 -0
  26. data/TODO.roadmap/19-error-model.md +45 -0
  27. data/TODO.roadmap/20-font-and-text.md +46 -0
  28. data/TODO.roadmap/21-images.md +45 -0
  29. data/TODO.roadmap/22-forms-and-resources.md +25 -0
  30. data/TODO.roadmap/23-level2-level3.md +52 -0
  31. data/TODO.roadmap/24-ci-and-release.md +42 -0
  32. data/TODO.roadmap/README.md +77 -0
  33. data/docs/.gitignore +29 -0
  34. data/docs/CHANGELOG.md +114 -0
  35. data/docs/COMPLETE_DOCUMENTATION_STATUS.md +376 -0
  36. data/docs/DEPLOYMENT.md +456 -0
  37. data/docs/DEPLOYMENT_INSTRUCTIONS.md +229 -0
  38. data/docs/DOCUMENTATION_PLAN.md +425 -0
  39. data/docs/FINAL_SUMMARY.md +657 -0
  40. data/docs/Gemfile +15 -0
  41. data/docs/README.md +327 -0
  42. data/docs/_config.yml +99 -0
  43. data/docs/advanced-topics.adoc +370 -0
  44. data/docs/api-reference/colors.adoc +705 -0
  45. data/docs/api-reference/converter.adoc +699 -0
  46. data/docs/api-reference/execution-context.adoc +1210 -0
  47. data/docs/api-reference/graphics-state.adoc +1070 -0
  48. data/docs/api-reference/interpreter.adoc +810 -0
  49. data/docs/api-reference/matrix.adoc +1179 -0
  50. data/docs/api-reference/path-builder.adoc +1284 -0
  51. data/docs/api-reference/postsvg-module.adoc +388 -0
  52. data/docs/api-reference/svg-generator.adoc +891 -0
  53. data/docs/api-reference/tokenizer.adoc +925 -0
  54. data/docs/api-reference.adoc +221 -0
  55. data/docs/architecture/command-registry.adoc +1191 -0
  56. data/docs/architecture/conversion-pipeline.adoc +746 -0
  57. data/docs/architecture/design-decisions.adoc +999 -0
  58. data/docs/architecture/generator-stage.adoc +1115 -0
  59. data/docs/architecture/graphics-state-model.adoc +1089 -0
  60. data/docs/architecture/interpreter-stage.adoc +1125 -0
  61. data/docs/architecture/parser-stage.adoc +1051 -0
  62. data/docs/architecture.adoc +354 -0
  63. data/docs/cli-reference/batch-command.adoc +616 -0
  64. data/docs/cli-reference/check-command.adoc +677 -0
  65. data/docs/cli-reference/cli-options.adoc +802 -0
  66. data/docs/cli-reference/convert-command.adoc +462 -0
  67. data/docs/cli-reference/version-command.adoc +296 -0
  68. data/docs/cli-reference.adoc +317 -0
  69. data/docs/concepts/conversion-pipeline.adoc +903 -0
  70. data/docs/concepts/coordinate-systems.adoc +836 -0
  71. data/docs/concepts/graphics-state.adoc +861 -0
  72. data/docs/concepts/path-operations.adoc +1076 -0
  73. data/docs/concepts/postscript-language.adoc +859 -0
  74. data/docs/concepts/svg-generation.adoc +937 -0
  75. data/docs/concepts.adoc +198 -0
  76. data/docs/contributing.adoc +443 -0
  77. data/docs/development.adoc +420 -0
  78. data/docs/faq.adoc +493 -0
  79. data/docs/getting-started/basic-usage.adoc +538 -0
  80. data/docs/getting-started/common-workflows.adoc +577 -0
  81. data/docs/getting-started/first-conversion.adoc +492 -0
  82. data/docs/getting-started/installation.adoc +534 -0
  83. data/docs/getting-started.adoc +94 -0
  84. data/docs/index.adoc +248 -0
  85. data/docs/optimization.adoc +196 -0
  86. data/docs/ps2svg_compatibility.adoc +149 -0
  87. data/docs/quick-reference.adoc +453 -0
  88. data/docs/sitemap.adoc +337 -0
  89. data/docs/troubleshooting.adoc +486 -0
  90. data/docs/validation.adoc +772 -0
  91. data/exe/postsvg +1 -0
  92. data/lib/postsvg/cli.rb +104 -57
  93. data/lib/postsvg/color.rb +132 -0
  94. data/lib/postsvg/errors.rb +68 -3
  95. data/lib/postsvg/format_number.rb +22 -0
  96. data/lib/postsvg/graphics_context.rb +80 -0
  97. data/lib/postsvg/graphics_stack.rb +43 -0
  98. data/lib/postsvg/model/literals/array.rb +41 -0
  99. data/lib/postsvg/model/literals/dictionary.rb +34 -0
  100. data/lib/postsvg/model/literals/hex.rb +37 -0
  101. data/lib/postsvg/model/literals/name.rb +40 -0
  102. data/lib/postsvg/model/literals/number.rb +36 -0
  103. data/lib/postsvg/model/literals/procedure.rb +41 -0
  104. data/lib/postsvg/model/literals/string.rb +30 -0
  105. data/lib/postsvg/model/literals.rb +19 -0
  106. data/lib/postsvg/model/operator.rb +58 -0
  107. data/lib/postsvg/model/operators/arithmetic.rb +264 -0
  108. data/lib/postsvg/model/operators/boolean.rb +182 -0
  109. data/lib/postsvg/model/operators/color.rb +74 -0
  110. data/lib/postsvg/model/operators/container.rb +186 -0
  111. data/lib/postsvg/model/operators/control_flow.rb +119 -0
  112. data/lib/postsvg/model/operators/device.rb +21 -0
  113. data/lib/postsvg/model/operators/dictionary.rb +118 -0
  114. data/lib/postsvg/model/operators/font.rb +121 -0
  115. data/lib/postsvg/model/operators/graphics_state.rb +84 -0
  116. data/lib/postsvg/model/operators/painting.rb +29 -0
  117. data/lib/postsvg/model/operators/path.rb +169 -0
  118. data/lib/postsvg/model/operators/stack.rb +72 -0
  119. data/lib/postsvg/model/operators/transformations.rb +103 -0
  120. data/lib/postsvg/model/operators.rb +89 -0
  121. data/lib/postsvg/model/program.rb +68 -0
  122. data/lib/postsvg/model/token.rb +43 -0
  123. data/lib/postsvg/model.rb +17 -0
  124. data/lib/postsvg/options.rb +29 -0
  125. data/lib/postsvg/renderer.rb +85 -0
  126. data/lib/postsvg/serializer.rb +325 -0
  127. data/lib/postsvg/source/ast_builder.rb +308 -0
  128. data/lib/postsvg/source/lexer.rb +322 -0
  129. data/lib/postsvg/source/operand_stack.rb +55 -0
  130. data/lib/postsvg/source.rb +21 -0
  131. data/lib/postsvg/svg/attribute_parser.rb +45 -0
  132. data/lib/postsvg/svg/clip_path_registry.rb +44 -0
  133. data/lib/postsvg/svg/document.rb +22 -0
  134. data/lib/postsvg/svg/element.rb +84 -0
  135. data/lib/postsvg/svg/elements/circle.rb +36 -0
  136. data/lib/postsvg/svg/elements/clip_path.rb +26 -0
  137. data/lib/postsvg/svg/elements/defs.rb +24 -0
  138. data/lib/postsvg/svg/elements/ellipse.rb +38 -0
  139. data/lib/postsvg/svg/elements/group.rb +37 -0
  140. data/lib/postsvg/svg/elements/image.rb +35 -0
  141. data/lib/postsvg/svg/elements/line.rb +36 -0
  142. data/lib/postsvg/svg/elements/path.rb +32 -0
  143. data/lib/postsvg/svg/elements/polygon.rb +12 -0
  144. data/lib/postsvg/svg/elements/polyline.rb +32 -0
  145. data/lib/postsvg/svg/elements/rect.rb +44 -0
  146. data/lib/postsvg/svg/elements/svg.rb +39 -0
  147. data/lib/postsvg/svg/elements/text.rb +42 -0
  148. data/lib/postsvg/svg/elements.rb +31 -0
  149. data/lib/postsvg/svg/paint.rb +34 -0
  150. data/lib/postsvg/svg/parser.rb +39 -0
  151. data/lib/postsvg/svg/path_data/command.rb +27 -0
  152. data/lib/postsvg/svg/path_data/parser.rb +82 -0
  153. data/lib/postsvg/svg/path_data.rb +17 -0
  154. data/lib/postsvg/svg/stroke.rb +31 -0
  155. data/lib/postsvg/svg/transform_list.rb +59 -0
  156. data/lib/postsvg/svg.rb +22 -0
  157. data/lib/postsvg/svg_builder.rb +249 -0
  158. data/lib/postsvg/translation/arc_converter.rb +86 -0
  159. data/lib/postsvg/translation/bounding_box.rb +59 -0
  160. data/lib/postsvg/translation/context.rb +34 -0
  161. data/lib/postsvg/translation/handler_registry.rb +38 -0
  162. data/lib/postsvg/translation/handlers/circle_handler.rb +28 -0
  163. data/lib/postsvg/translation/handlers/clip_path_handler.rb +13 -0
  164. data/lib/postsvg/translation/handlers/defs_handler.rb +15 -0
  165. data/lib/postsvg/translation/handlers/ellipse_handler.rb +31 -0
  166. data/lib/postsvg/translation/handlers/group_handler.rb +21 -0
  167. data/lib/postsvg/translation/handlers/image_handler.rb +20 -0
  168. data/lib/postsvg/translation/handlers/line_handler.rb +23 -0
  169. data/lib/postsvg/translation/handlers/open_handler.rb +18 -0
  170. data/lib/postsvg/translation/handlers/path_handler.rb +356 -0
  171. data/lib/postsvg/translation/handlers/polygon_handler.rb +33 -0
  172. data/lib/postsvg/translation/handlers/polyline_handler.rb +31 -0
  173. data/lib/postsvg/translation/handlers/rect_handler.rb +27 -0
  174. data/lib/postsvg/translation/handlers/shared.rb +110 -0
  175. data/lib/postsvg/translation/handlers/svg_handler.rb +25 -0
  176. data/lib/postsvg/translation/handlers/text_handler.rb +56 -0
  177. data/lib/postsvg/translation/handlers.rb +25 -0
  178. data/lib/postsvg/translation/ps_renderer.rb +105 -0
  179. data/lib/postsvg/translation/record_emitter.rb +35 -0
  180. data/lib/postsvg/translation.rb +17 -0
  181. data/lib/postsvg/version.rb +1 -1
  182. data/lib/postsvg/visitors/ps_visitor/arithmetic.rb +125 -0
  183. data/lib/postsvg/visitors/ps_visitor/boolean.rb +105 -0
  184. data/lib/postsvg/visitors/ps_visitor/color.rb +53 -0
  185. data/lib/postsvg/visitors/ps_visitor/common.rb +66 -0
  186. data/lib/postsvg/visitors/ps_visitor/container.rb +164 -0
  187. data/lib/postsvg/visitors/ps_visitor/control_flow.rb +110 -0
  188. data/lib/postsvg/visitors/ps_visitor/device.rb +20 -0
  189. data/lib/postsvg/visitors/ps_visitor/dictionary.rb +89 -0
  190. data/lib/postsvg/visitors/ps_visitor/font.rb +93 -0
  191. data/lib/postsvg/visitors/ps_visitor/graphics_state.rb +55 -0
  192. data/lib/postsvg/visitors/ps_visitor/painting.rb +90 -0
  193. data/lib/postsvg/visitors/ps_visitor/path.rb +112 -0
  194. data/lib/postsvg/visitors/ps_visitor/stack.rb +47 -0
  195. data/lib/postsvg/visitors/ps_visitor/transformations.rb +101 -0
  196. data/lib/postsvg/visitors/ps_visitor.rb +208 -0
  197. data/lib/postsvg/visitors.rb +9 -0
  198. data/lib/postsvg.rb +93 -59
  199. data/lychee.toml +86 -0
  200. metadata +216 -11
  201. data/postsvg.gemspec +0 -38
@@ -0,0 +1,772 @@
1
+ = PostSVG Validation Guide
2
+ :toc: left
3
+ :toclevels: 3
4
+ :sectnums:
5
+
6
+ == Introduction
7
+
8
+ PostSVG includes a comprehensive validation tool for PostScript and EPS files. The validator helps identify syntax errors, semantic issues, and structural problems before attempting conversion to SVG.
9
+
10
+ == Quick Start
11
+
12
+ === Basic Usage
13
+
14
+ Validate a single file:
15
+
16
+ [source,shell]
17
+ ----
18
+ postsvg check document.ps
19
+ ----
20
+
21
+ Validate multiple files:
22
+
23
+ [source,shell]
24
+ ----
25
+ postsvg check file1.ps file2.eps file3.ps
26
+ ----
27
+
28
+ Validate all PostScript files in directory:
29
+
30
+ [source,shell]
31
+ ----
32
+ postsvg check *.ps
33
+ ----
34
+
35
+ == Validation Levels
36
+
37
+ PostSVG provides three validation levels, each building on the previous:
38
+
39
+ === Syntax Level (Fast)
40
+
41
+ The syntax level performs basic structural checks without executing PostScript code.
42
+
43
+ *Checks performed:*
44
+
45
+ * Header format validation (PS vs EPS)
46
+ * BoundingBox validation for EPS files
47
+ * Delimiter balance (parentheses, brackets, braces)
48
+ * Basic tokenization
49
+ * EOF marker presence
50
+
51
+ *Usage:*
52
+
53
+ [source,shell]
54
+ ----
55
+ postsvg check --level=syntax file.ps
56
+ ----
57
+
58
+ *When to use:*
59
+
60
+ * Quick validation of many files
61
+ * Pre-processing check before batch conversion
62
+ * CI/CD pipeline early validation
63
+ * Syntax-only linting
64
+
65
+ === Semantic Level (Default)
66
+
67
+ The semantic level adds PostScript operator analysis without full conversion.
68
+
69
+ *Checks performed:*
70
+
71
+ * All syntax checks
72
+ * Stack balance simulation
73
+ * Graphics state tracking (gsave/grestore pairs)
74
+ * Dictionary tracking (dict begin/end pairs)
75
+ * Operator coverage checking
76
+
77
+ *Usage:*
78
+
79
+ [source,shell]
80
+ ----
81
+ postsvg check file.ps
82
+ postsvg check --level=semantic file.ps
83
+ ----
84
+
85
+ *When to use:*
86
+
87
+ * Default validation for most use cases
88
+ * Detecting logical errors before conversion
89
+ * Ensuring PostScript semantic correctness
90
+
91
+ === Full Level (Strict)
92
+
93
+ The full level performs complete conversion attempt for strictest validation.
94
+
95
+ *Checks performed:*
96
+
97
+ * All semantic checks
98
+ * Complete PostScript interpretation
99
+ * Full conversion to SVG
100
+ * All PostScript operator execution
101
+
102
+ *Usage:*
103
+
104
+ [source,shell]
105
+ ----
106
+ postsvg check --level=full file.ps
107
+ ----
108
+
109
+ *When to use:*
110
+
111
+ * Final validation before production
112
+ * Testing conversion compatibility
113
+ * Debugging complex PostScript files
114
+
115
+ == Output Formats
116
+
117
+ === Text Format (Default)
118
+
119
+ Human-readable colorized output with visual indicators.
120
+
121
+ *Usage:*
122
+
123
+ [source,shell]
124
+ ----
125
+ postsvg check file.ps
126
+ ----
127
+
128
+ *Example output:*
129
+
130
+ [source,text]
131
+ ----
132
+ ✓ file.ps is valid
133
+
134
+ ✗ broken.ps has errors:
135
+ ERROR: Unclosed string literal at line 5
136
+ ERROR: Stack underflow at line 10
137
+ WARNING: Unmatched gsave at line 15
138
+ ----
139
+
140
+ *Options:*
141
+
142
+ * `--verbose`: Show warnings and info messages
143
+ * `--quiet`: Suppress valid file messages
144
+ * `--no-color`: Disable colored output
145
+
146
+ === YAML Format
147
+
148
+ Structured output suitable for parsing and automation.
149
+
150
+ *Usage:*
151
+
152
+ [source,shell]
153
+ ----
154
+ postsvg check --format=yaml file.ps
155
+ ----
156
+
157
+ *Example output:*
158
+
159
+ [source,yaml]
160
+ ----
161
+ file.ps:
162
+ valid: true
163
+ errors: []
164
+ warnings: []
165
+ info: []
166
+
167
+ broken.ps:
168
+ valid: false
169
+ errors:
170
+ - "Unclosed string literal at line 5"
171
+ - "Stack underflow at line 10"
172
+ warnings:
173
+ - "Unmatched gsave at line 15"
174
+ info: []
175
+ ----
176
+
177
+ === JSON Format
178
+
179
+ Machine-readable JSON output for integration with other tools.
180
+
181
+ *Usage:*
182
+
183
+ [source,shell]
184
+ ----
185
+ postsvg check --format=json file.ps
186
+ ----
187
+
188
+ *Example output:*
189
+
190
+ [source,json]
191
+ ----
192
+ {
193
+ "file.ps": {
194
+ "valid": true,
195
+ "errors": [],
196
+ "warnings": [],
197
+ "info": []
198
+ },
199
+ "broken.ps": {
200
+ "valid": false,
201
+ "errors": [
202
+ "Unclosed string literal at line 5",
203
+ "Stack underflow at line 10"
204
+ ],
205
+ "warnings": [
206
+ "Unmatched gsave at line 15"
207
+ ],
208
+ "info": []
209
+ }
210
+ }
211
+ ----
212
+
213
+ == Validation Options
214
+
215
+ === Verbose Mode
216
+
217
+ Display all messages including warnings and informational messages.
218
+
219
+ [source,shell]
220
+ ----
221
+ postsvg check --verbose file.ps
222
+ ----
223
+
224
+ *Shows:*
225
+
226
+ * All errors
227
+ * All warnings
228
+ * All informational messages
229
+ * Operator coverage information
230
+
231
+ === Quiet Mode
232
+
233
+ Suppress messages for valid files, only show errors.
234
+
235
+ [source,shell]
236
+ ----
237
+ postsvg check --quiet *.ps
238
+ ----
239
+
240
+ *Use cases:*
241
+
242
+ * Batch validation of many files
243
+ * Focus on problematic files only
244
+ * Cleaner CI/CD output
245
+
246
+ === Fail-Fast Mode
247
+
248
+ Stop validation at the first error encountered.
249
+
250
+ [source,shell]
251
+ ----
252
+ postsvg check --fail-fast file1.ps file2.ps file3.ps
253
+ ----
254
+
255
+ *Behavior:*
256
+
257
+ * Processes files in order
258
+ * Stops immediately when error found
259
+ * Returns exit code 1
260
+ * Useful for rapid error detection
261
+
262
+ === Color Control
263
+
264
+ Disable colored output for log files or non-terminal environments.
265
+
266
+ [source,shell]
267
+ ----
268
+ postsvg check --no-color file.ps > validation.log
269
+ ----
270
+
271
+ === EPS Version Validation
272
+
273
+ Validate EPS version compliance for specific PostScript levels.
274
+
275
+ [source,shell]
276
+ ----
277
+ postsvg check --eps-version=3.0 diagram.eps
278
+ ----
279
+
280
+ *Supported versions:*
281
+
282
+ * 1.0 - Basic EPS
283
+ * 2.0 - Level 2 PostScript
284
+ * 3.0 - Level 3 PostScript
285
+
286
+ == Common Validation Errors
287
+
288
+ === Delimiter Imbalance
289
+
290
+ *Error:* `Unclosed string literal`
291
+
292
+ *Cause:* Missing closing parenthesis in string.
293
+
294
+ *Example:*
295
+
296
+ [source,postscript]
297
+ ----
298
+ (Hello World % Missing )
299
+ ----
300
+
301
+ *Fix:*
302
+
303
+ [source,postscript]
304
+ ----
305
+ (Hello World)
306
+ ----
307
+
308
+ === Stack Underflow
309
+
310
+ *Error:* `Stack underflow`
311
+
312
+ *Cause:* Operator requires more values than available on stack.
313
+
314
+ *Example:*
315
+
316
+ [source,postscript]
317
+ ----
318
+ pop % Stack is empty
319
+ ----
320
+
321
+ *Fix:*
322
+
323
+ [source,postscript]
324
+ ----
325
+ 5 pop % Push value before popping
326
+ ----
327
+
328
+ === Unmatched Graphics State
329
+
330
+ *Warning:* `Unmatched gsave/grestore`
331
+
332
+ *Cause:* Missing grestore for gsave operation.
333
+
334
+ *Example:*
335
+
336
+ [source,postscript]
337
+ ----
338
+ gsave
339
+ 1 0 0 setrgbcolor
340
+ 100 100 moveto
341
+ % Missing grestore
342
+ ----
343
+
344
+ *Fix:*
345
+
346
+ [source,postscript]
347
+ ----
348
+ gsave
349
+ 1 0 0 setrgbcolor
350
+ 100 100 moveto
351
+ grestore
352
+ ----
353
+
354
+ === Missing BoundingBox
355
+
356
+ *Error:* `EPS file missing required BoundingBox comment`
357
+
358
+ *Cause:* EPS file lacks required `%%BoundingBox` header.
359
+
360
+ *Example:*
361
+
362
+ [source,postscript]
363
+ ----
364
+ %!PS-Adobe-3.0 EPSF-3.0
365
+ % Missing %%BoundingBox
366
+ ----
367
+
368
+ *Fix:*
369
+
370
+ [source,postscript]
371
+ ----
372
+ %!PS-Adobe-3.0 EPSF-3.0
373
+ %%BoundingBox: 0 0 612 792
374
+ ----
375
+
376
+ === Dictionary Imbalance
377
+
378
+ *Warning:* `Unmatched dict begin/end`
379
+
380
+ *Cause:* Dictionary started but not ended, or vice versa.
381
+
382
+ *Example:*
383
+
384
+ [source,postscript]
385
+ ----
386
+ 10 dict begin
387
+ /key1 value1 def
388
+ % Missing end
389
+ ----
390
+
391
+ *Fix:*
392
+
393
+ [source,postscript]
394
+ ----
395
+ 10 dict begin
396
+ /key1 value1 def
397
+ end
398
+ ----
399
+
400
+ == Exit Codes
401
+
402
+ PostSVG validation returns standard exit codes for CI/CD integration:
403
+
404
+ * `0` - All files valid, no errors
405
+ * `1` - One or more files have errors
406
+
407
+ === CI/CD Integration
408
+
409
+ ==== GitHub Actions
410
+
411
+ [source,yaml]
412
+ ----
413
+ name: Validate PostScript Files
414
+ on: [push, pull_request]
415
+
416
+ jobs:
417
+ validate:
418
+ runs-on: ubuntu-latest
419
+ steps:
420
+ - uses: actions/checkout@v3
421
+ - uses: ruby/setup-ruby@v1
422
+ with:
423
+ ruby-version: '3.2'
424
+ - run: gem install postsvg
425
+ - run: postsvg check --fail-fast --format=json *.ps
426
+ ----
427
+
428
+ ==== GitLab CI
429
+
430
+ [source,yaml]
431
+ ----
432
+ validate:
433
+ image: ruby:3.2
434
+ script:
435
+ - gem install postsvg
436
+ - postsvg check --format=yaml --no-color *.ps
437
+ artifacts:
438
+ reports:
439
+ junit: validation-report.xml
440
+ ----
441
+
442
+ ==== Jenkins
443
+
444
+ [source,groovy]
445
+ ----
446
+ stage('Validate PostScript') {
447
+ steps {
448
+ sh 'gem install postsvg'
449
+ sh 'postsvg check --fail-fast *.ps'
450
+ }
451
+ }
452
+ ----
453
+
454
+ == Advanced Usage
455
+
456
+ === Batch Processing
457
+
458
+ Validate all PostScript files in directory tree:
459
+
460
+ [source,shell]
461
+ ----
462
+ find . -name "*.ps" -exec postsvg check --quiet {} \;
463
+ ----
464
+
465
+ Generate validation report:
466
+
467
+ [source,shell]
468
+ ----
469
+ postsvg check --format=json *.ps > validation-report.json
470
+ ----
471
+
472
+ === Pre-commit Hook
473
+
474
+ Add validation to Git pre-commit hook:
475
+
476
+ [source,shell]
477
+ ----
478
+ #!/bin/sh
479
+ # .git/hooks/pre-commit
480
+
481
+ # Get list of PostScript files being committed
482
+ PS_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.ps$')
483
+
484
+ if [ -n "$PS_FILES" ]; then
485
+ echo "Validating PostScript files..."
486
+ for file in $PS_FILES; do
487
+ postsvg check --fail-fast "$file" || exit 1
488
+ done
489
+ fi
490
+ ----
491
+
492
+ === Automated Testing
493
+
494
+ Use validation in RSpec tests:
495
+
496
+ [source,ruby]
497
+ ----
498
+ require 'postsvg'
499
+
500
+ RSpec.describe "PostScript Files" do
501
+ Dir.glob("spec/fixtures/**/*.ps").each do |file|
502
+ it "#{file} is valid" do
503
+ result = `postsvg check --format=json #{file}`
504
+ data = JSON.parse(result)
505
+ expect(data.dig(file, "valid")).to be true
506
+ end
507
+ end
508
+ end
509
+ ----
510
+
511
+ == Best Practices
512
+
513
+ === Development Workflow
514
+
515
+ . Use syntax level during development for quick feedback
516
+ . Use semantic level before committing changes
517
+ . Use full level before production deployment
518
+
519
+ === File Organization
520
+
521
+ . Keep test fixtures in `spec/fixtures/validation/`
522
+ . Organize by valid/invalid categories
523
+ . Use descriptive filenames indicating error type
524
+
525
+ === Documentation
526
+
527
+ . Document expected validation results in fixtures
528
+ . Include validation level requirements in README
529
+ . Add validation examples to user documentation
530
+
531
+ === Performance
532
+
533
+ . Use syntax level for large batch operations
534
+ . Enable fail-fast for quick error detection
535
+ . Use quiet mode for cleaner output in automation
536
+
537
+ == Troubleshooting
538
+
539
+ === Validator Returns False Positives
540
+
541
+ *Issue:* Valid PostScript reported as invalid.
542
+
543
+ *Solutions:*
544
+
545
+ . Check PostScript version compatibility
546
+ . Verify operator support in PostSVG
547
+ . Use `--verbose` to see detailed messages
548
+ . Test with `--level=syntax` to isolate issue
549
+
550
+ === Validator Misses Errors
551
+
552
+ *Issue:* Invalid PostScript reported as valid.
553
+
554
+ *Solutions:*
555
+
556
+ . Use higher validation level (`--level=full`)
557
+ . Enable verbose mode to see warnings
558
+ . Check if error is semantic vs syntactic
559
+ . Report issue with sample file
560
+
561
+ === Performance Issues
562
+
563
+ *Issue:* Validation is slow for large files.
564
+
565
+ *Solutions:*
566
+
567
+ . Use `--level=syntax` for initial checks
568
+ . Enable `--fail-fast` for quicker failure
569
+ . Process files in parallel using shell tools
570
+ . Consider file size and complexity
571
+
572
+ == API Usage
573
+
574
+ === Ruby API
575
+
576
+ Use validation programmatically in Ruby:
577
+
578
+ [source,ruby]
579
+ ----
580
+ require 'postsvg'
581
+
582
+ # Validate a file
583
+ service = Postsvg::ValidationService.new(
584
+ level: :semantic,
585
+ fail_fast: false,
586
+ verbose: false
587
+ )
588
+
589
+ result = service.validate_file('document.ps')
590
+
591
+ if result.valid?
592
+ puts "File is valid"
593
+ else
594
+ puts "Errors:"
595
+ result.error_messages.each { |msg| puts " #{msg}" }
596
+ end
597
+ ----
598
+
599
+ === Validation Result Object
600
+
601
+ [source,ruby]
602
+ ----
603
+ # Access validation details
604
+ result.valid? # => true/false
605
+ result.error_count # => Integer
606
+ result.warning_count # => Integer
607
+ result.info_count # => Integer
608
+
609
+ result.error_messages # => Array of error strings
610
+ result.warning_messages # => Array of warning strings
611
+ result.info_messages # => Array of info strings
612
+
613
+ result.all_messages # => Hash with all messages by severity
614
+ ----
615
+
616
+ === Custom Reporters
617
+
618
+ Create custom reporter for specific output format:
619
+
620
+ [source,ruby]
621
+ ----
622
+ class CustomReporter
623
+ def report(results)
624
+ # results is Hash of filename => ValidationResult
625
+ results.each do |file, result|
626
+ # Custom formatting logic
627
+ end
628
+ end
629
+ end
630
+
631
+ # Use custom reporter
632
+ reporter = CustomReporter.new
633
+ reporter.report(validation_results)
634
+ ----
635
+
636
+ == Architecture
637
+
638
+ === Component Diagram
639
+
640
+ [source]
641
+ ----
642
+ ┌─────────────────────────────────────────────────────────┐
643
+ │ CLI Command │
644
+ │ (check command) │
645
+ └───────────────────────┬─────────────────────────────────┘
646
+
647
+
648
+ ┌─────────────────────────────────────────────────────────┐
649
+ │ ValidationService │
650
+ │ • Orchestrates validation process │
651
+ │ • Manages validation levels │
652
+ │ • Implements fail-fast logic │
653
+ └───────────────────────┬─────────────────────────────────┘
654
+
655
+ ┌───────────────┼───────────────┐
656
+ ▼ ▼ ▼
657
+ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
658
+ │ Syntax │ │ Semantic │ │ Full │
659
+ │ Validator │ │ Validator │ │ Validator │
660
+ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘
661
+ │ │ │
662
+ │ │ │
663
+ └───────────────┴───────────────┘
664
+
665
+
666
+ ┌──────────────────────┐
667
+ │ ValidationResult │
668
+ │ • Errors │
669
+ │ • Warnings │
670
+ │ • Info messages │
671
+ └──────────┬───────────┘
672
+
673
+ ┌───────────────┼───────────────┐
674
+ ▼ ▼ ▼
675
+ ┌───────────┐ ┌──────────────┐ ┌──────────────┐
676
+ │ Text │ │ YAML │ │ JSON │
677
+ │ Reporter │ │ Reporter │ │ Reporter │
678
+ └───────────┘ └──────────────┘ └──────────────┘
679
+ ----
680
+
681
+ === Validator Classes
682
+
683
+ ==== SyntaxValidator
684
+
685
+ Performs structural validation without PostScript execution:
686
+
687
+ * Header format checking
688
+ * BoundingBox validation
689
+ * Delimiter balance
690
+ * Token validity
691
+
692
+ ==== SemanticValidator
693
+
694
+ Analyzes PostScript semantics:
695
+
696
+ * Stack simulation
697
+ * Graphics state tracking
698
+ * Dictionary tracking
699
+ * Operator coverage
700
+
701
+ ==== Helper Classes
702
+
703
+ * *DelimiterChecker* - Validates balanced delimiters
704
+ * *StackSimulator* - Simulates PostScript stack
705
+ * *GraphicsStateTracker* - Tracks gsave/grestore
706
+ * *DictionaryTracker* - Tracks dict begin/end
707
+
708
+ == Reference
709
+
710
+ === Command Line Options
711
+
712
+ [cols="2,3,2",options="header"]
713
+ |===
714
+ | Option | Description | Default
715
+
716
+ | `--level=LEVEL`
717
+ | Validation level (syntax/semantic/full)
718
+ | semantic
719
+
720
+ | `--format=FORMAT`
721
+ | Output format (text/yaml/json)
722
+ | text
723
+
724
+ | `--verbose`
725
+ | Show warnings and info messages
726
+ | false
727
+
728
+ | `--quiet`
729
+ | Suppress valid file messages
730
+ | false
731
+
732
+ | `--no-color`
733
+ | Disable colored output
734
+ | false
735
+
736
+ | `--fail-fast`
737
+ | Stop at first error
738
+ | false
739
+
740
+ | `--eps-version=VERSION`
741
+ | EPS version to validate (1.0/2.0/3.0)
742
+ | none
743
+ |===
744
+
745
+ === Message Severities
746
+
747
+ [cols="2,3",options="header"]
748
+ |===
749
+ | Severity | Description
750
+
751
+ | ERROR
752
+ | Critical issues preventing conversion
753
+
754
+ | WARNING
755
+ | Potential problems that may affect output
756
+
757
+ | INFO
758
+ | Informational messages about file structure
759
+ |===
760
+
761
+ === Supported File Types
762
+
763
+ * `.ps` - PostScript files
764
+ * `.eps` - Encapsulated PostScript files
765
+ * Any text file with PostScript content
766
+
767
+ == Further Reading
768
+
769
+ * link:../README.adoc[PostSVG README]
770
+ * link:ps2svg_compatibility.adoc[PS2SVG Compatibility Guide]
771
+ * link:postscript/index.adoc[PostScript Implementation Notes]
772
+ * link:optimization.adoc[Optimization Guide]