lutaml-openapi 0.1.2 → 0.1.3

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.
data/script/axe_audit ADDED
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ # axe-core accessibility audit of the generated SPA. Uses the axe-core
4
+ # copy vendored by the frontend's npm devDependencies (sovereign: no CDN
5
+ # fetch). Exits non-zero when violations are found; skips cleanly when
6
+ # no Chrome binary or no built frontend exists, so `rake` stays green on
7
+ # browser-less lanes (windows CI) while the browser-equipped lanes
8
+ # (ubuntu/macos) always run it.
9
+
10
+ require "json"
11
+ require "open3"
12
+ require "fileutils"
13
+ require "tmpdir"
14
+ require "lutaml/openapi"
15
+
16
+ CHROME_CANDIDATES = [
17
+ ENV.fetch("CHROME_BIN", nil),
18
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
19
+ "/usr/bin/chromium",
20
+ "/usr/bin/chromium-browser",
21
+ "/usr/bin/google-chrome",
22
+ ].freeze
23
+
24
+ ROOT = File.expand_path("..", __dir__)
25
+ DOCUMENT = ARGV.first ||
26
+ File.join(ROOT, "spec", "fixtures", "ogcapi-features-1-oas31.yaml")
27
+
28
+ chrome = CHROME_CANDIDATES.find { |path| path && File.executable?(path) }
29
+ unless chrome
30
+ warn "axe audit: SKIP (no Chrome binary; set CHROME_BIN to enable)"
31
+ exit 0
32
+ end
33
+
34
+ dist = File.join(ROOT, "frontend", "dist")
35
+ unless File.exist?(File.join(dist, "app.iife.js"))
36
+ warn "axe audit: SKIP (frontend/dist missing; run `rake frontend:build`)"
37
+ exit 0
38
+ end
39
+
40
+ axe = File.join(ROOT, "frontend", "node_modules", "axe-core", "axe.min.js")
41
+ unless File.exist?(axe)
42
+ abort "axe audit: frontend/node_modules/axe-core missing; " \
43
+ "run `npm install` in frontend/"
44
+ end
45
+
46
+ INJECT = <<~SCRIPT
47
+ <script src="file://#{axe}"></script>
48
+ <script>
49
+ window.addEventListener('load', () => setTimeout(() => {
50
+ axe.run().then((r) => {
51
+ document.body.setAttribute('data-axe', JSON.stringify({
52
+ violations: r.violations.map((v) => ({ id: v.id, impact: v.impact,
53
+ nodes: v.nodes.length,
54
+ targets: v.nodes.map((n) => n.target.join(' ')) })),
55
+ passes: r.passes.length,
56
+ }));
57
+ document.title = 'AXE-DONE';
58
+ }).catch((e) => {
59
+ document.body.setAttribute('data-axe', JSON.stringify({ error: String(e) }));
60
+ document.title = 'AXE-ERROR';
61
+ });
62
+ }, 4000));
63
+ </script>
64
+ SCRIPT
65
+
66
+ dir = Dir.mktmpdir("axe-audit")
67
+ document = Lutaml::Openapi.parse(File.read(DOCUMENT))
68
+ File.write(File.join(dir, "index.html"), Lutaml::Openapi::Spa.generate(document))
69
+
70
+ page = File.join(dir, "index.html")
71
+ File.write(File.join(dir, "audit.html"),
72
+ File.read(page).sub("</body>", "#{INJECT}\n</body>"))
73
+
74
+ # both locales gate: the default LTR render and the Arabic RTL render
75
+ # (the mirrored layout must stay accessible)
76
+ VARIANTS = [
77
+ { label: "en", query: "" },
78
+ { label: "ar (rtl)", query: "?locale=ar" },
79
+ ].freeze
80
+
81
+ failed = false
82
+
83
+ VARIANTS.each do |variant|
84
+ dom, err, status = Open3.capture3(
85
+ chrome, "--headless=new", "--disable-gpu", "--virtual-time-budget=20000",
86
+ "--dump-dom", "file://#{File.join(dir, 'audit.html')}#{variant[:query]}"
87
+ )
88
+ abort "axe audit: Chrome failed: #{err[0, 400]}" unless status.success?
89
+
90
+ match = dom[/data-axe="([^"]*)"/, 1]
91
+ abort "axe audit (#{variant[:label]}): no result captured" unless match
92
+
93
+ result = JSON.parse(match.gsub("&quot;", '"'))
94
+ abort "axe audit: axe failed: #{result['error']}" if result["error"]
95
+
96
+ if result["violations"].empty?
97
+ puts "axe audit (#{variant[:label]}): PASS (#{result['passes']} rule groups)"
98
+ else
99
+ failed = true
100
+ puts "axe audit (#{variant[:label]}): " \
101
+ "#{result['violations'].sum { |v| v['nodes'] }} violations"
102
+ result["violations"].each do |violation|
103
+ puts " [#{violation['impact']}] #{violation['id']} x#{violation['nodes']}"
104
+ violation["targets"].each { |target| puts " #{target}" }
105
+ end
106
+ end
107
+ end
108
+
109
+ exit 1 if failed
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-openapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-10-28 00:00:00.000000000 Z
11
+ date: 2026-10-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.6.34
61
+ version: 0.6.51
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.6.34
68
+ version: 0.6.51
69
69
  description: Parse OpenAPI 3.0/3.1 documents into lossless LutaML model objects; the
70
70
  model layer for model-based OpenAPI standards
71
71
  email:
@@ -87,10 +87,13 @@ files:
87
87
  - frontend/package-lock.json
88
88
  - frontend/package.json
89
89
  - frontend/src/App.vue
90
+ - frontend/src/__tests__/i18n.test.ts
90
91
  - frontend/src/app.ts
91
92
  - frontend/src/components/OverviewView.vue
92
93
  - frontend/src/components/PathsView.vue
93
94
  - frontend/src/components/SchemasView.vue
95
+ - frontend/src/i18n/index.ts
96
+ - frontend/src/i18n/messages.ts
94
97
  - frontend/src/style.css
95
98
  - frontend/tsconfig.json
96
99
  - frontend/vite.config.ts
@@ -101,6 +104,7 @@ files:
101
104
  - lib/lutaml/openapi/spa.rb
102
105
  - lib/lutaml/openapi/version.rb
103
106
  - rakelib/corpus.rake
107
+ - script/axe_audit
104
108
  homepage: https://github.com/lutaml/lutaml-openapi
105
109
  licenses:
106
110
  - BSD-2-Clause