@navios/react-query 0.7.1 → 1.0.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 (117) hide show
  1. package/CHANGELOG.md +171 -1
  2. package/README.md +152 -4
  3. package/coverage/base.css +224 -0
  4. package/coverage/block-navigation.js +87 -0
  5. package/coverage/client/declare-client.mts.html +1264 -0
  6. package/coverage/client/index.html +116 -0
  7. package/coverage/clover.xml +160 -0
  8. package/coverage/coverage-final.json +8 -0
  9. package/coverage/favicon.png +0 -0
  10. package/coverage/index.html +146 -0
  11. package/coverage/mutation/index.html +131 -0
  12. package/coverage/mutation/key-creator.mts.html +277 -0
  13. package/coverage/mutation/make-hook.mts.html +952 -0
  14. package/coverage/prettify.css +1 -0
  15. package/coverage/prettify.js +2 -0
  16. package/coverage/query/index.html +161 -0
  17. package/coverage/query/key-creator.mts.html +415 -0
  18. package/coverage/query/make-infinite-options.mts.html +601 -0
  19. package/coverage/query/make-options.mts.html +838 -0
  20. package/coverage/query/prefetch.mts.html +1063 -0
  21. package/coverage/sort-arrow-sprite.png +0 -0
  22. package/coverage/sorter.js +210 -0
  23. package/dist/src/__tests__/errorSchema.spec.d.mts +2 -0
  24. package/dist/src/__tests__/errorSchema.spec.d.mts.map +1 -0
  25. package/dist/src/__tests__/prefetch.spec.d.mts +2 -0
  26. package/dist/src/__tests__/prefetch.spec.d.mts.map +1 -0
  27. package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts +2 -0
  28. package/dist/src/client/__type-tests__/from-endpoint.spec-d.d.mts.map +1 -0
  29. package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts +2 -0
  30. package/dist/src/client/__type-tests__/infinite-query.spec-d.d.mts.map +1 -0
  31. package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts +2 -0
  32. package/dist/src/client/__type-tests__/multipart-mutation.spec-d.d.mts.map +1 -0
  33. package/dist/src/client/__type-tests__/mutation.spec-d.d.mts +2 -0
  34. package/dist/src/client/__type-tests__/mutation.spec-d.d.mts.map +1 -0
  35. package/dist/src/client/__type-tests__/query.spec-d.d.mts +2 -0
  36. package/dist/src/client/__type-tests__/query.spec-d.d.mts.map +1 -0
  37. package/dist/src/client/declare-client.d.mts +15 -8
  38. package/dist/src/client/declare-client.d.mts.map +1 -1
  39. package/dist/src/client/types/from-endpoint.d.mts +130 -0
  40. package/dist/src/client/types/from-endpoint.d.mts.map +1 -0
  41. package/dist/src/client/types/helpers.d.mts +74 -0
  42. package/dist/src/client/types/helpers.d.mts.map +1 -0
  43. package/dist/src/client/types/index.d.mts +21 -0
  44. package/dist/src/client/types/index.d.mts.map +1 -0
  45. package/dist/src/client/types/infinite-query.d.mts +61 -0
  46. package/dist/src/client/types/infinite-query.d.mts.map +1 -0
  47. package/dist/src/client/types/multipart-mutation.d.mts +98 -0
  48. package/dist/src/client/types/multipart-mutation.d.mts.map +1 -0
  49. package/dist/src/client/types/mutation.d.mts +75 -0
  50. package/dist/src/client/types/mutation.d.mts.map +1 -0
  51. package/dist/src/client/types/query.d.mts +65 -0
  52. package/dist/src/client/types/query.d.mts.map +1 -0
  53. package/dist/src/client/types.d.mts +1 -608
  54. package/dist/src/client/types.d.mts.map +1 -1
  55. package/dist/src/common/types.d.mts +40 -3
  56. package/dist/src/common/types.d.mts.map +1 -1
  57. package/dist/src/mutation/index.d.mts +1 -0
  58. package/dist/src/mutation/index.d.mts.map +1 -1
  59. package/dist/src/mutation/make-hook.d.mts +42 -16
  60. package/dist/src/mutation/make-hook.d.mts.map +1 -1
  61. package/dist/src/mutation/optimistic.d.mts +172 -0
  62. package/dist/src/mutation/optimistic.d.mts.map +1 -0
  63. package/dist/src/mutation/types.d.mts +41 -20
  64. package/dist/src/mutation/types.d.mts.map +1 -1
  65. package/dist/src/query/index.d.mts +1 -0
  66. package/dist/src/query/index.d.mts.map +1 -1
  67. package/dist/src/query/key-creator.d.mts.map +1 -1
  68. package/dist/src/query/make-infinite-options.d.mts +3 -2
  69. package/dist/src/query/make-infinite-options.d.mts.map +1 -1
  70. package/dist/src/query/make-options.d.mts +42 -12
  71. package/dist/src/query/make-options.d.mts.map +1 -1
  72. package/dist/src/query/prefetch.d.mts +245 -0
  73. package/dist/src/query/prefetch.d.mts.map +1 -0
  74. package/dist/src/query/types.d.mts +25 -18
  75. package/dist/src/query/types.d.mts.map +1 -1
  76. package/dist/tsconfig.tsbuildinfo +1 -1
  77. package/lib/index.cjs +451 -28
  78. package/lib/index.cjs.map +1 -1
  79. package/lib/index.d.cts +1019 -600
  80. package/lib/index.d.cts.map +1 -1
  81. package/lib/index.d.mts +1016 -597
  82. package/lib/index.d.mts.map +1 -1
  83. package/lib/index.mjs +447 -29
  84. package/lib/index.mjs.map +1 -1
  85. package/package.json +3 -3
  86. package/src/__tests__/declare-client.spec.mts +229 -2
  87. package/src/__tests__/errorSchema.spec.mts +391 -0
  88. package/src/__tests__/make-mutation.spec.mts +6 -5
  89. package/src/__tests__/makeDataTag.spec.mts +2 -1
  90. package/src/__tests__/makeQueryOptions.spec.mts +2 -1
  91. package/src/__tests__/prefetch.spec.mts +310 -0
  92. package/src/client/__type-tests__/from-endpoint.spec-d.mts +550 -0
  93. package/src/client/__type-tests__/infinite-query.spec-d.mts +648 -0
  94. package/src/client/__type-tests__/multipart-mutation.spec-d.mts +725 -0
  95. package/src/client/__type-tests__/mutation.spec-d.mts +757 -0
  96. package/src/client/__type-tests__/query.spec-d.mts +701 -0
  97. package/src/client/declare-client.mts +59 -34
  98. package/src/client/types/from-endpoint.mts +344 -0
  99. package/src/client/types/helpers.mts +140 -0
  100. package/src/client/types/index.mts +26 -0
  101. package/src/client/types/infinite-query.mts +133 -0
  102. package/src/client/types/multipart-mutation.mts +264 -0
  103. package/src/client/types/mutation.mts +176 -0
  104. package/src/client/types/query.mts +132 -0
  105. package/src/client/types.mts +1 -1935
  106. package/src/common/types.mts +67 -3
  107. package/src/mutation/index.mts +1 -0
  108. package/src/mutation/make-hook.mts +171 -63
  109. package/src/mutation/optimistic.mts +300 -0
  110. package/src/mutation/types.mts +87 -30
  111. package/src/query/index.mts +1 -0
  112. package/src/query/key-creator.mts +24 -13
  113. package/src/query/make-infinite-options.mts +53 -10
  114. package/src/query/make-options.mts +184 -43
  115. package/src/query/prefetch.mts +326 -0
  116. package/src/query/types.mts +56 -17
  117. package/src/client/__type-tests__/client-instance.spec-d.mts +0 -852
package/CHANGELOG.md CHANGED
@@ -1,6 +1,176 @@
1
1
  # Changelog
2
2
 
3
- ## [0.7.1] - 2025-12-20
3
+ ## [1.0.0] - 2026-01-08
4
+
5
+ ### Highlights
6
+
7
+ This is the first stable release of `@navios/react-query`. It includes major improvements to type safety, new helpers for common patterns like optimistic updates and SSR prefetching, and full support for discriminated union error handling.
8
+
9
+ ### Changed
10
+
11
+ - **Optimistic Update Helpers Marked Experimental**: `createOptimisticUpdate` and `createMultiOptimisticUpdate` are now marked as `@experimental`. These APIs may change in future versions - use manual optimistic update patterns for production code until these helpers stabilize.
12
+
13
+ ## [1.0.0-alpha.1] - 2026-01-07
14
+
15
+ ### Highlights
16
+
17
+ This was a pre-release version of `@navios/react-query`.
18
+
19
+ ### Breaking Changes
20
+
21
+ - **Type file reorganization** - Client types have been split into modular files for better maintainability:
22
+ - `client/types.mts` → Split into `client/types/query.mts`, `client/types/mutation.mts`, `client/types/infinite-query.mts`, `client/types/multipart-mutation.mts`, `client/types/from-endpoint.mts`, and `client/types/helpers.mts`
23
+ - If you were importing internal types directly, update your imports to use the new paths or the re-exported types from the main entry point.
24
+
25
+ ### Added
26
+
27
+ #### Error Schema Support (Discriminated Union Mode)
28
+
29
+ Full support for `errorSchema` in queries and mutations when using `useDiscriminatorResponse: true` mode. API error responses are now returned as data (not thrown) and can be discriminated by status code:
30
+
31
+ ```typescript
32
+ const api = builder({ useDiscriminatorResponse: true })
33
+
34
+ const getUser = client.query({
35
+ method: 'GET',
36
+ url: '/users/$userId',
37
+ responseSchema: userSchema,
38
+ errorSchema: {
39
+ 400: z.object({ error: z.string(), code: z.number() }),
40
+ 404: z.object({ notFound: z.literal(true) }),
41
+ },
42
+ processResponse: (data) => {
43
+ // data is typed as: User | { error: string, code: number } | { notFound: true }
44
+ if ('error' in data) {
45
+ return { ok: false, error: data.error }
46
+ }
47
+ if ('notFound' in data) {
48
+ return { ok: false, error: 'User not found' }
49
+ }
50
+ return { ok: true, user: data }
51
+ },
52
+ })
53
+ ```
54
+
55
+ #### SSR/RSC Prefetch Helpers
56
+
57
+ New `createPrefetchHelper` and `createPrefetchHelpers` utilities for server-side rendering and React Server Components:
58
+
59
+ ```typescript
60
+ import { createPrefetchHelper, prefetchAll } from '@navios/react-query'
61
+ import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
62
+
63
+ // Create prefetch helper from query
64
+ const userPrefetch = createPrefetchHelper(getUser)
65
+
66
+ // Server Component
67
+ async function UserPage({ userId }: { userId: string }) {
68
+ const queryClient = new QueryClient()
69
+
70
+ await userPrefetch.prefetch(queryClient, { urlParams: { userId } })
71
+
72
+ return (
73
+ <HydrationBoundary state={dehydrate(queryClient)}>
74
+ <UserProfile userId={userId} />
75
+ </HydrationBoundary>
76
+ )
77
+ }
78
+ ```
79
+
80
+ **Prefetch helper methods:**
81
+
82
+ - `prefetch(queryClient, params)` - Prefetch data on the server
83
+ - `ensureData(queryClient, params)` - Ensure data exists, returns the data
84
+ - `getQueryOptions(params)` - Get raw query options for customization
85
+ - `prefetchMany(queryClient, paramsList)` - Prefetch multiple queries in parallel
86
+
87
+ **Batch prefetching:**
88
+
89
+ ```typescript
90
+ // Create multiple prefetch helpers at once
91
+ const prefetchers = createPrefetchHelpers({
92
+ user: getUser,
93
+ posts: getUserPosts,
94
+ })
95
+
96
+ // Or use prefetchAll for different queries
97
+ await prefetchAll(queryClient, [
98
+ { helper: userPrefetch, params: { urlParams: { userId } } },
99
+ {
100
+ helper: postsPrefetch,
101
+ params: { urlParams: { userId }, params: { limit: 10 } },
102
+ },
103
+ ])
104
+ ```
105
+
106
+ #### Optimistic Update Helpers
107
+
108
+ New `createOptimisticUpdate` and `createMultiOptimisticUpdate` utilities for type-safe optimistic updates:
109
+
110
+ ```typescript
111
+ import {
112
+ createMultiOptimisticUpdate,
113
+ createOptimisticUpdate,
114
+ } from '@navios/react-query'
115
+
116
+ const updateUser = client.mutation({
117
+ method: 'PATCH',
118
+ url: '/users/$userId',
119
+ requestSchema: updateUserSchema,
120
+ responseSchema: userSchema,
121
+ processResponse: (data) => data,
122
+ useContext: () => ({ queryClient: useQueryClient() }),
123
+ ...createOptimisticUpdate({
124
+ queryKey: ['users', userId],
125
+ updateFn: (oldData, variables) => ({
126
+ ...oldData,
127
+ ...variables.data,
128
+ }),
129
+ rollbackOnError: true, // default
130
+ invalidateOnSettled: true, // default
131
+ }),
132
+ })
133
+ ```
134
+
135
+ **Multi-query optimistic updates:**
136
+
137
+ ```typescript
138
+ const updateUser = client.mutation({
139
+ // ...
140
+ ...createMultiOptimisticUpdate([
141
+ {
142
+ queryKey: ['users', userId],
143
+ updateFn: (oldData, variables) => ({ ...oldData, ...variables.data }),
144
+ },
145
+ {
146
+ queryKey: ['users'],
147
+ updateFn: (oldList, variables) =>
148
+ (oldList ?? []).map((u) =>
149
+ u.id === userId ? { ...u, ...variables.data } : u,
150
+ ),
151
+ },
152
+ ]),
153
+ })
154
+ ```
155
+
156
+ #### New Type Exports
157
+
158
+ - `ComputeBaseResult<UseDiscriminator, Response, ErrorSchema>` - Compute result type based on discriminator mode
159
+ - `PrefetchHelper<TParams, TData, TError>` - Type for prefetch helper instances
160
+ - `QueryOptionsCreator<TParams, TData, TError>` - Type for query options creator functions
161
+ - `OptimisticUpdateConfig<TData, TVariables, TQueryData>` - Configuration for optimistic updates
162
+ - `OptimisticUpdateCallbacks<TData, TVariables, TQueryData>` - Return type from `createOptimisticUpdate`
163
+
164
+ ### Changed
165
+
166
+ - **Improved type inference** - Better type inference for `processResponse` callbacks, especially when using `errorSchema`
167
+ - **Modular type definitions** - Client types are now organized into separate files by concern:
168
+ - `types/query.mts` - Query-related types
169
+ - `types/mutation.mts` - Mutation-related types
170
+ - `types/infinite-query.mts` - Infinite query types
171
+ - `types/multipart-mutation.mts` - Multipart mutation types
172
+ - `types/from-endpoint.mts` - Types for `*FromEndpoint` methods
173
+ - `types/helpers.mts` - Helper types like `EndpointHelper`, `StreamHelper`, `ComputeBaseResult`
4
174
 
5
175
  ### Fixed
6
176
 
package/README.md CHANGED
@@ -9,7 +9,9 @@ Type-safe React Query integration for Navios API client with Zod schema validati
9
9
  - **React Query Integration** - Seamless integration with TanStack Query v5
10
10
  - **Declarative API** - Define endpoints once, use everywhere
11
11
  - **URL Parameters** - Built-in support for parameterized URLs (`/users/$userId`)
12
- - **Optimistic Updates** - First-class support via `onMutate` callback
12
+ - **Optimistic Updates** - First-class helpers via `createOptimisticUpdate`
13
+ - **SSR/RSC Support** - Built-in prefetch helpers for server-side rendering
14
+ - **Error Schema Support** - Type-safe error handling with discriminated unions
13
15
  - **Stream Support** - Handle file downloads and blob responses
14
16
 
15
17
  ## Installation
@@ -514,6 +516,148 @@ function AvatarUpload({ userId }: { userId: string }) {
514
516
  }
515
517
  ```
516
518
 
519
+ ## SSR/RSC Prefetch Helpers
520
+
521
+ For server-side rendering and React Server Components, use the prefetch helpers:
522
+
523
+ ```typescript
524
+ import { createPrefetchHelper, prefetchAll } from '@navios/react-query'
525
+ import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'
526
+
527
+ // Create prefetch helper from your query
528
+ const userPrefetch = createPrefetchHelper(getUser)
529
+
530
+ // Server Component
531
+ async function UserPage({ userId }: { userId: string }) {
532
+ const queryClient = new QueryClient()
533
+
534
+ await userPrefetch.prefetch(queryClient, { urlParams: { userId } })
535
+
536
+ return (
537
+ <HydrationBoundary state={dehydrate(queryClient)}>
538
+ <UserProfile userId={userId} />
539
+ </HydrationBoundary>
540
+ )
541
+ }
542
+ ```
543
+
544
+ ### Batch Prefetching
545
+
546
+ ```typescript
547
+ // Create multiple helpers at once
548
+ const prefetchers = createPrefetchHelpers({
549
+ user: getUser,
550
+ posts: getUserPosts,
551
+ })
552
+
553
+ // Or prefetch different queries in parallel
554
+ await prefetchAll(queryClient, [
555
+ { helper: userPrefetch, params: { urlParams: { userId } } },
556
+ { helper: postsPrefetch, params: { urlParams: { userId }, params: { limit: 10 } } },
557
+ ])
558
+ ```
559
+
560
+ ### Helper Methods
561
+
562
+ - `prefetch(queryClient, params)` - Prefetch data on the server
563
+ - `ensureData(queryClient, params)` - Ensure data exists, returns the data
564
+ - `getQueryOptions(params)` - Get raw query options for customization
565
+ - `prefetchMany(queryClient, paramsList)` - Prefetch multiple queries in parallel
566
+
567
+ ## Optimistic Update Helpers
568
+
569
+ Simplify optimistic updates with the `createOptimisticUpdate` helper:
570
+
571
+ ```typescript
572
+ import { createOptimisticUpdate } from '@navios/react-query'
573
+
574
+ const updateUser = client.mutation({
575
+ method: 'PATCH',
576
+ url: '/users/$userId',
577
+ requestSchema: updateUserSchema,
578
+ responseSchema: userSchema,
579
+ processResponse: (data) => data,
580
+ useContext: () => ({ queryClient: useQueryClient() }),
581
+ ...createOptimisticUpdate({
582
+ queryKey: ['users', userId],
583
+ updateFn: (oldData, variables) => ({
584
+ ...oldData,
585
+ ...variables.data,
586
+ }),
587
+ rollbackOnError: true, // default
588
+ invalidateOnSettled: true, // default
589
+ }),
590
+ })
591
+ ```
592
+
593
+ ### Multi-Query Optimistic Updates
594
+
595
+ When a mutation affects multiple cached queries:
596
+
597
+ ```typescript
598
+ import { createMultiOptimisticUpdate } from '@navios/react-query'
599
+
600
+ const updateUser = client.mutation({
601
+ // ...config
602
+ ...createMultiOptimisticUpdate([
603
+ {
604
+ queryKey: ['users', userId],
605
+ updateFn: (oldData, variables) => ({ ...oldData, ...variables.data }),
606
+ },
607
+ {
608
+ queryKey: ['users'],
609
+ updateFn: (oldList, variables) =>
610
+ (oldList ?? []).map((u) =>
611
+ u.id === userId ? { ...u, ...variables.data } : u
612
+ ),
613
+ },
614
+ ]),
615
+ })
616
+ ```
617
+
618
+ ## Error Schema Support
619
+
620
+ When using `useDiscriminatorResponse: true` mode, API errors are returned as data instead of being thrown. This enables type-safe error discrimination:
621
+
622
+ ```typescript
623
+ const api = builder({ useDiscriminatorResponse: true })
624
+
625
+ const getUser = client.query({
626
+ method: 'GET',
627
+ url: '/users/$userId',
628
+ responseSchema: userSchema,
629
+ errorSchema: {
630
+ 400: z.object({ error: z.string(), code: z.number() }),
631
+ 404: z.object({ notFound: z.literal(true) }),
632
+ 500: z.object({ serverError: z.string() }),
633
+ },
634
+ processResponse: (data) => {
635
+ // data is typed as: User | { error: string, code: number } | { notFound: true } | { serverError: string }
636
+ if ('error' in data) {
637
+ return { ok: false as const, error: data.error }
638
+ }
639
+ if ('notFound' in data) {
640
+ return { ok: false as const, error: 'User not found' }
641
+ }
642
+ if ('serverError' in data) {
643
+ return { ok: false as const, error: data.serverError }
644
+ }
645
+ return { ok: true as const, user: data }
646
+ },
647
+ })
648
+
649
+ // In your component
650
+ function UserProfile({ userId }: { userId: string }) {
651
+ const result = getUser.useSuspense({ urlParams: { userId } })
652
+
653
+ if (!result.ok) {
654
+ return <ErrorMessage error={result.error} />
655
+ }
656
+
657
+ return <div>{result.user.name}</div>
658
+ }
659
+ ```
660
+
517
661
  ## API Reference
518
662
 
519
663
  ### `declareClient(options)`
@@ -594,11 +738,15 @@ The context passed to mutation callbacks includes:
594
738
  - `meta` - Mutation metadata
595
739
  - `onMutateResult` - Return value from `onMutate` (in `onSuccess`, `onError`, `onSettled`)
596
740
 
597
- ## Migration from 0.5.x
741
+ ## Migration to 1.0.0
742
+
743
+ See [CHANGELOG.md](./CHANGELOG.md) for full migration guide.
744
+
745
+ ### From 0.7.x
598
746
 
599
- See [CHANGELOG.md](./CHANGELOG.md) for migration guide from 0.5.x to 0.6.0.
747
+ - **Type file reorganization** - If importing internal types, update paths to use `client/types/*.mts`
600
748
 
601
- Key changes:
749
+ ### From 0.5.x to 0.6.x
602
750
 
603
751
  - Mutation callbacks now receive `(data, variables, context)` instead of `(queryClient, data, variables)`
604
752
  - Use `useContext` hook to provide `queryClient` and other dependencies
@@ -0,0 +1,224 @@
1
+ body, html {
2
+ margin:0; padding: 0;
3
+ height: 100%;
4
+ }
5
+ body {
6
+ font-family: Helvetica Neue, Helvetica, Arial;
7
+ font-size: 14px;
8
+ color:#333;
9
+ }
10
+ .small { font-size: 12px; }
11
+ *, *:after, *:before {
12
+ -webkit-box-sizing:border-box;
13
+ -moz-box-sizing:border-box;
14
+ box-sizing:border-box;
15
+ }
16
+ h1 { font-size: 20px; margin: 0;}
17
+ h2 { font-size: 14px; }
18
+ pre {
19
+ font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace;
20
+ margin: 0;
21
+ padding: 0;
22
+ -moz-tab-size: 2;
23
+ -o-tab-size: 2;
24
+ tab-size: 2;
25
+ }
26
+ a { color:#0074D9; text-decoration:none; }
27
+ a:hover { text-decoration:underline; }
28
+ .strong { font-weight: bold; }
29
+ .space-top1 { padding: 10px 0 0 0; }
30
+ .pad2y { padding: 20px 0; }
31
+ .pad1y { padding: 10px 0; }
32
+ .pad2x { padding: 0 20px; }
33
+ .pad2 { padding: 20px; }
34
+ .pad1 { padding: 10px; }
35
+ .space-left2 { padding-left:55px; }
36
+ .space-right2 { padding-right:20px; }
37
+ .center { text-align:center; }
38
+ .clearfix { display:block; }
39
+ .clearfix:after {
40
+ content:'';
41
+ display:block;
42
+ height:0;
43
+ clear:both;
44
+ visibility:hidden;
45
+ }
46
+ .fl { float: left; }
47
+ @media only screen and (max-width:640px) {
48
+ .col3 { width:100%; max-width:100%; }
49
+ .hide-mobile { display:none!important; }
50
+ }
51
+
52
+ .quiet {
53
+ color: #7f7f7f;
54
+ color: rgba(0,0,0,0.5);
55
+ }
56
+ .quiet a { opacity: 0.7; }
57
+
58
+ .fraction {
59
+ font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace;
60
+ font-size: 10px;
61
+ color: #555;
62
+ background: #E8E8E8;
63
+ padding: 4px 5px;
64
+ border-radius: 3px;
65
+ vertical-align: middle;
66
+ }
67
+
68
+ div.path a:link, div.path a:visited { color: #333; }
69
+ table.coverage {
70
+ border-collapse: collapse;
71
+ margin: 10px 0 0 0;
72
+ padding: 0;
73
+ }
74
+
75
+ table.coverage td {
76
+ margin: 0;
77
+ padding: 0;
78
+ vertical-align: top;
79
+ }
80
+ table.coverage td.line-count {
81
+ text-align: right;
82
+ padding: 0 5px 0 20px;
83
+ }
84
+ table.coverage td.line-coverage {
85
+ text-align: right;
86
+ padding-right: 10px;
87
+ min-width:20px;
88
+ }
89
+
90
+ table.coverage td span.cline-any {
91
+ display: inline-block;
92
+ padding: 0 5px;
93
+ width: 100%;
94
+ }
95
+ .missing-if-branch {
96
+ display: inline-block;
97
+ margin-right: 5px;
98
+ border-radius: 3px;
99
+ position: relative;
100
+ padding: 0 4px;
101
+ background: #333;
102
+ color: yellow;
103
+ }
104
+
105
+ .skip-if-branch {
106
+ display: none;
107
+ margin-right: 10px;
108
+ position: relative;
109
+ padding: 0 4px;
110
+ background: #ccc;
111
+ color: white;
112
+ }
113
+ .missing-if-branch .typ, .skip-if-branch .typ {
114
+ color: inherit !important;
115
+ }
116
+ .coverage-summary {
117
+ border-collapse: collapse;
118
+ width: 100%;
119
+ }
120
+ .coverage-summary tr { border-bottom: 1px solid #bbb; }
121
+ .keyline-all { border: 1px solid #ddd; }
122
+ .coverage-summary td, .coverage-summary th { padding: 10px; }
123
+ .coverage-summary tbody { border: 1px solid #bbb; }
124
+ .coverage-summary td { border-right: 1px solid #bbb; }
125
+ .coverage-summary td:last-child { border-right: none; }
126
+ .coverage-summary th {
127
+ text-align: left;
128
+ font-weight: normal;
129
+ white-space: nowrap;
130
+ }
131
+ .coverage-summary th.file { border-right: none !important; }
132
+ .coverage-summary th.pct { }
133
+ .coverage-summary th.pic,
134
+ .coverage-summary th.abs,
135
+ .coverage-summary td.pct,
136
+ .coverage-summary td.abs { text-align: right; }
137
+ .coverage-summary td.file { white-space: nowrap; }
138
+ .coverage-summary td.pic { min-width: 120px !important; }
139
+ .coverage-summary tfoot td { }
140
+
141
+ .coverage-summary .sorter {
142
+ height: 10px;
143
+ width: 7px;
144
+ display: inline-block;
145
+ margin-left: 0.5em;
146
+ background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent;
147
+ }
148
+ .coverage-summary .sorted .sorter {
149
+ background-position: 0 -20px;
150
+ }
151
+ .coverage-summary .sorted-desc .sorter {
152
+ background-position: 0 -10px;
153
+ }
154
+ .status-line { height: 10px; }
155
+ /* yellow */
156
+ .cbranch-no { background: yellow !important; color: #111; }
157
+ /* dark red */
158
+ .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 }
159
+ .low .chart { border:1px solid #C21F39 }
160
+ .highlighted,
161
+ .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{
162
+ background: #C21F39 !important;
163
+ }
164
+ /* medium red */
165
+ .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE }
166
+ /* light red */
167
+ .low, .cline-no { background:#FCE1E5 }
168
+ /* light green */
169
+ .high, .cline-yes { background:rgb(230,245,208) }
170
+ /* medium green */
171
+ .cstat-yes { background:rgb(161,215,106) }
172
+ /* dark green */
173
+ .status-line.high, .high .cover-fill { background:rgb(77,146,33) }
174
+ .high .chart { border:1px solid rgb(77,146,33) }
175
+ /* dark yellow (gold) */
176
+ .status-line.medium, .medium .cover-fill { background: #f9cd0b; }
177
+ .medium .chart { border:1px solid #f9cd0b; }
178
+ /* light yellow */
179
+ .medium { background: #fff4c2; }
180
+
181
+ .cstat-skip { background: #ddd; color: #111; }
182
+ .fstat-skip { background: #ddd; color: #111 !important; }
183
+ .cbranch-skip { background: #ddd !important; color: #111; }
184
+
185
+ span.cline-neutral { background: #eaeaea; }
186
+
187
+ .coverage-summary td.empty {
188
+ opacity: .5;
189
+ padding-top: 4px;
190
+ padding-bottom: 4px;
191
+ line-height: 1;
192
+ color: #888;
193
+ }
194
+
195
+ .cover-fill, .cover-empty {
196
+ display:inline-block;
197
+ height: 12px;
198
+ }
199
+ .chart {
200
+ line-height: 0;
201
+ }
202
+ .cover-empty {
203
+ background: white;
204
+ }
205
+ .cover-full {
206
+ border-right: none !important;
207
+ }
208
+ pre.prettyprint {
209
+ border: none !important;
210
+ padding: 0 !important;
211
+ margin: 0 !important;
212
+ }
213
+ .com { color: #999 !important; }
214
+ .ignore-none { color: #999; font-weight: normal; }
215
+
216
+ .wrapper {
217
+ min-height: 100%;
218
+ height: auto !important;
219
+ height: 100%;
220
+ margin: 0 auto -48px;
221
+ }
222
+ .footer, .push {
223
+ height: 48px;
224
+ }
@@ -0,0 +1,87 @@
1
+ /* eslint-disable */
2
+ var jumpToCode = (function init() {
3
+ // Classes of code we would like to highlight in the file view
4
+ var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
5
+
6
+ // Elements to highlight in the file listing view
7
+ var fileListingElements = ['td.pct.low'];
8
+
9
+ // We don't want to select elements that are direct descendants of another match
10
+ var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
11
+
12
+ // Selector that finds elements on the page to which we can jump
13
+ var selector =
14
+ fileListingElements.join(', ') +
15
+ ', ' +
16
+ notSelector +
17
+ missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
18
+
19
+ // The NodeList of matching elements
20
+ var missingCoverageElements = document.querySelectorAll(selector);
21
+
22
+ var currentIndex;
23
+
24
+ function toggleClass(index) {
25
+ missingCoverageElements
26
+ .item(currentIndex)
27
+ .classList.remove('highlighted');
28
+ missingCoverageElements.item(index).classList.add('highlighted');
29
+ }
30
+
31
+ function makeCurrent(index) {
32
+ toggleClass(index);
33
+ currentIndex = index;
34
+ missingCoverageElements.item(index).scrollIntoView({
35
+ behavior: 'smooth',
36
+ block: 'center',
37
+ inline: 'center'
38
+ });
39
+ }
40
+
41
+ function goToPrevious() {
42
+ var nextIndex = 0;
43
+ if (typeof currentIndex !== 'number' || currentIndex === 0) {
44
+ nextIndex = missingCoverageElements.length - 1;
45
+ } else if (missingCoverageElements.length > 1) {
46
+ nextIndex = currentIndex - 1;
47
+ }
48
+
49
+ makeCurrent(nextIndex);
50
+ }
51
+
52
+ function goToNext() {
53
+ var nextIndex = 0;
54
+
55
+ if (
56
+ typeof currentIndex === 'number' &&
57
+ currentIndex < missingCoverageElements.length - 1
58
+ ) {
59
+ nextIndex = currentIndex + 1;
60
+ }
61
+
62
+ makeCurrent(nextIndex);
63
+ }
64
+
65
+ return function jump(event) {
66
+ if (
67
+ document.getElementById('fileSearch') === document.activeElement &&
68
+ document.activeElement != null
69
+ ) {
70
+ // if we're currently focused on the search input, we don't want to navigate
71
+ return;
72
+ }
73
+
74
+ switch (event.which) {
75
+ case 78: // n
76
+ case 74: // j
77
+ goToNext();
78
+ break;
79
+ case 66: // b
80
+ case 75: // k
81
+ case 80: // p
82
+ goToPrevious();
83
+ break;
84
+ }
85
+ };
86
+ })();
87
+ window.addEventListener('keydown', jumpToCode);