@teleporthq/teleport-plugin-common 0.43.59 → 0.43.60

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.
@@ -24,6 +24,29 @@ describe('CSS Class Generation', () => {
24
24
  expect(result).toEqual(`.name h1 > h2 .ab.cd #id {
25
25
  some-key: value;
26
26
  other-key: otherValue;
27
+ }`)
28
+ })
29
+
30
+ it('attaches an ATTRIBUTE subselector with no separating space', () => {
31
+ // ⛔ THE SELECTED-PAGE CONTRACT. A numbered pagination strip repeats one
32
+ // authored node per visible page, so the copies cannot differ in the
33
+ // document. Both runtimes instead mark the showing page with
34
+ // `aria-current="page"` (`numbered-pagination.ts` here, `element-node.tsx`
35
+ // in the canvas editor), and the LOOK is a compound project class whose
36
+ // subselector is that attribute.
37
+ //
38
+ // A space before the bracket would turn this into a DESCENDANT selector —
39
+ // `.thq-page-number [aria-current='page']` matches something INSIDE the
40
+ // button, never the button — and the selected page would silently render
41
+ // identically to every other one. Which is exactly the bug the marker was
42
+ // added to fix.
43
+ const result = createCSSClassWithSelector('thq-page-number', "&[aria-current='page']", {
44
+ background: '#2563eb',
45
+ fontWeight: '600',
46
+ })
47
+ expect(result).toEqual(`.thq-page-number[aria-current='page'] {
48
+ background: #2563eb;
49
+ font-weight: 600;
27
50
  }`)
28
51
  })
29
52
  })
@@ -0,0 +1,239 @@
1
+ import * as types from '@babel/types'
2
+ import generator from '@babel/generator'
3
+ import {
4
+ QUERY_SYNC_REF_ID,
5
+ QUERY_WRITER_ID,
6
+ buildQuerySettledExpr,
7
+ buildQuerySyncDeclarations,
8
+ buildQueryWriteCall,
9
+ ensureQuerySyncDeclarations,
10
+ hasQuerySyncDeclarations,
11
+ } from '../../src/utils/url-query-writer'
12
+
13
+ const codeOf = (nodes: types.Statement[]): string =>
14
+ generator(types.program(nodes) as types.Node).code
15
+
16
+ /**
17
+ * A router that behaves like Next's.
18
+ *
19
+ * The two properties that caused the defect are reproduced faithfully:
20
+ * • `replace` resolves ASYNCHRONOUSLY, and `query` is only updated when it
21
+ * does — so a second writer running in the same tick still sees the old one;
22
+ * • `query` is a fresh object each time, as `makePublicRouterInstance` makes it.
23
+ */
24
+ const makeRouter = (initialQuery: Record<string, string>) => {
25
+ const replaced: Array<Record<string, string>> = []
26
+ let resolveAll: Array<() => void> = []
27
+ const router = {
28
+ pathname: '/products',
29
+ query: { ...initialQuery },
30
+ replace(url: { query: Record<string, string> }) {
31
+ replaced.push({ ...url.query })
32
+ return new Promise<boolean>((resolve) => {
33
+ resolveAll.push(() => {
34
+ // Next applies the navigation, THEN resolves.
35
+ router.query = { ...url.query }
36
+ resolve(true)
37
+ })
38
+ })
39
+ },
40
+ }
41
+ const settleAll = async (): Promise<void> => {
42
+ while (resolveAll.length > 0) {
43
+ const pending = resolveAll
44
+ resolveAll = []
45
+ pending.forEach((fn) => fn())
46
+ await Promise.resolve()
47
+ await Promise.resolve()
48
+ }
49
+ }
50
+ return { router, replaced, settleAll }
51
+ }
52
+
53
+ /** Evaluates the emitted declarations and hands back the writer they define. */
54
+ const instantiate = (router: unknown) => {
55
+ const code = codeOf(buildQuerySyncDeclarations())
56
+ // tslint:disable-next-line:function-constructor
57
+ const factory = new Function(
58
+ 'useRef',
59
+ 'router',
60
+ `${code}\nreturn { ref: ${QUERY_SYNC_REF_ID}, write: ${QUERY_WRITER_ID} }`
61
+ )
62
+ // tslint:disable-next-line:no-any
63
+ const useRef = (initial: any) => ({ current: initial })
64
+ return factory(useRef, router) as {
65
+ ref: { current: { pending: Record<string, string> | null; inFlight: number } }
66
+ // tslint:disable-next-line:no-any
67
+ write: (key: string, value: any) => void
68
+ }
69
+ }
70
+
71
+ describe('URLQueryWriter — emitted shape', () => {
72
+ it('merges into the pending query, not into router.query', () => {
73
+ // Babel prints objects multi-line; the assertions read better flattened.
74
+ const code = codeOf(buildQuerySyncDeclarations()).replace(/\s+/g, ' ')
75
+
76
+ expect(code).toContain('const base = __tqQuerySyncRef.current.pending || router.query')
77
+ expect(code).toContain('const next = { ...base }')
78
+ // The only bail: this key already holds the value we would write.
79
+ expect(code).toContain('if (next[key] === base[key]) return')
80
+ expect(code).toContain('__tqQuerySyncRef.current.pending = next')
81
+ expect(code).toContain('__tqQuerySyncRef.current.inFlight += 1')
82
+ // Released once every replace it was built from has settled, so an external
83
+ // navigation is never merged into a stale snapshot.
84
+ expect(code).toContain('__tqQuerySyncRef.current.pending = null')
85
+ expect(code).toContain('shallow: true')
86
+ })
87
+
88
+ it('builds a call and a settled-check callers can compose', () => {
89
+ expect(generator(buildQueryWriteCall('page', types.identifier('__statePage'))).code).toBe(
90
+ '__tqWriteQueryParam("page", __statePage);'
91
+ )
92
+ expect(generator(buildQuerySettledExpr()).code).toBe('__tqQuerySyncRef.current.inFlight === 0')
93
+ })
94
+
95
+ it('declares itself once, after `const router = useRouter()`', () => {
96
+ const routerDecl = types.variableDeclaration('const', [
97
+ types.variableDeclarator(
98
+ types.identifier('router'),
99
+ types.callExpression(types.identifier('useRouter'), [])
100
+ ),
101
+ ])
102
+ const body: types.Statement[] = [routerDecl, types.returnStatement(types.nullLiteral())]
103
+
104
+ expect(hasQuerySyncDeclarations(body)).toBe(false)
105
+ expect(ensureQuerySyncDeclarations(body)).toBe(true)
106
+ expect(body.length).toBe(4)
107
+ expect(codeOf(body).indexOf('useRouter')).toBeLessThan(codeOf(body).indexOf(QUERY_SYNC_REF_ID))
108
+
109
+ // A second plugin needing the same pair must not emit a duplicate hook —
110
+ // that would also shift the hook order between renders.
111
+ expect(ensureQuerySyncDeclarations(body)).toBe(false)
112
+ expect(body.length).toBe(4)
113
+ })
114
+ })
115
+
116
+ /**
117
+ * ⛔ These run the generated code. Every other guard in this repo is a
118
+ * source-text assertion, and effect INTERLEAVING is exactly what source text
119
+ * cannot see — which is why the defect below shipped green.
120
+ */
121
+ describe('URLQueryWriter — behaviour under a Next-like async router', () => {
122
+ it('keeps both keys when two controls write in the same flush', async () => {
123
+ // The live repro: on `?page=5`, picking a category writes the filter AND
124
+ // resets the page, so both writers run before either replace has landed.
125
+ const { router, replaced, settleAll } = makeRouter({ page: '5' })
126
+ const { write } = instantiate(router)
127
+
128
+ write('categoryFilter', 'Rings')
129
+ write('page', undefined) // page 1 ⇒ remove the key
130
+
131
+ expect(replaced).toHaveLength(2)
132
+ // The SECOND write built on the first's payload rather than on the stale
133
+ // `router.query` — this is the whole fix.
134
+ expect(replaced[1]).toEqual({ categoryFilter: 'Rings' })
135
+
136
+ await settleAll()
137
+ expect(router.query).toEqual({ categoryFilter: 'Rings' })
138
+ })
139
+
140
+ it('does not resurrect a key another writer removed in the same flush', async () => {
141
+ // The mirror image: clearing the search box on page 3 removes
142
+ // `?searchKeyword` and resets the page. A stale base would have put the
143
+ // search term the visitor just deleted straight back into the URL.
144
+ const { router, replaced, settleAll } = makeRouter({ page: '3', searchKeyword: 'shoes' })
145
+ const { write } = instantiate(router)
146
+
147
+ write('searchKeyword', '')
148
+ write('page', undefined)
149
+
150
+ expect(replaced[1]).toEqual({})
151
+ await settleAll()
152
+ expect(router.query).toEqual({})
153
+ })
154
+
155
+ it('settles, and never oscillates when both sides are re-asserted', async () => {
156
+ // Re-running every writer after the URL lands — which is what a re-render
157
+ // does — must produce NO further navigation. An extra replace here is the
158
+ // first step of the infinite loop.
159
+ const { router, replaced, settleAll } = makeRouter({ page: '5' })
160
+ const { write } = instantiate(router)
161
+
162
+ write('categoryFilter', 'Rings')
163
+ write('page', undefined)
164
+ await settleAll()
165
+
166
+ const settledCount = replaced.length
167
+ write('categoryFilter', 'Rings')
168
+ write('page', undefined)
169
+ expect(replaced).toHaveLength(settledCount)
170
+ })
171
+
172
+ it('bails without a replace when the key already holds the value', () => {
173
+ const { router, replaced } = makeRouter({ sortBy: 'price-asc' })
174
+ const { write } = instantiate(router)
175
+
176
+ write('sortBy', 'price-asc')
177
+ expect(replaced).toHaveLength(0)
178
+
179
+ // ...and removing an absent key is equally a no-op.
180
+ write('missing', undefined)
181
+ expect(replaced).toHaveLength(0)
182
+ })
183
+
184
+ it('coerces to a string, so a numeric page and a string filter round-trip alike', () => {
185
+ const { router, replaced } = makeRouter({})
186
+ const { write } = instantiate(router)
187
+
188
+ write('page', 3)
189
+ expect(replaced[0]).toEqual({ page: '3' })
190
+ })
191
+
192
+ it('reports settled only once every replace it issued has landed', async () => {
193
+ const { router, settleAll } = makeRouter({ page: '5' })
194
+ const { ref, write } = instantiate(router)
195
+
196
+ expect(ref.current.inFlight).toBe(0)
197
+ write('categoryFilter', 'Rings')
198
+ write('page', undefined)
199
+ // The page ⇄ URL effect reads this to know that `router.query` is a value
200
+ // the page is on its way OUT of, and must not be adopted.
201
+ expect(ref.current.inFlight).toBe(2)
202
+
203
+ await settleAll()
204
+ expect(ref.current.inFlight).toBe(0)
205
+ expect(ref.current.pending).toBeNull()
206
+ })
207
+
208
+ it('releases the pending query even when a navigation is rejected', async () => {
209
+ // A cancelled route must not freeze every later write against a stale base.
210
+ const router = {
211
+ pathname: '/products',
212
+ query: { page: '5' } as Record<string, string>,
213
+ replace: () => Promise.reject(new Error('route cancelled')),
214
+ }
215
+ const { ref, write } = instantiate(router)
216
+
217
+ write('categoryFilter', 'Rings')
218
+ await Promise.resolve()
219
+ await Promise.resolve()
220
+
221
+ expect(ref.current.inFlight).toBe(0)
222
+ expect(ref.current.pending).toBeNull()
223
+ })
224
+
225
+ it('picks up an external navigation once nothing is in flight', async () => {
226
+ // Browser back/forward moves the URL without asking us. The next write must
227
+ // build on where the browser actually is, not on our last request.
228
+ const { router, replaced, settleAll } = makeRouter({ page: '5' })
229
+ const { write } = instantiate(router)
230
+
231
+ write('categoryFilter', 'Rings')
232
+ await settleAll()
233
+
234
+ router.query = { locale: 'fr' } // an external navigation
235
+ write('page', 2)
236
+
237
+ expect(replaced[replaced.length - 1]).toEqual({ locale: 'fr', page: '2' })
238
+ })
239
+ })
@@ -11,7 +11,7 @@ import {
11
11
  const codeOf = (node: types.Node): string => generator(node).code
12
12
 
13
13
  describe('URLSearchParamSync.buildUrlWriteBackEffect', () => {
14
- it('emits a loop-free state→URL write-back for a bare state identifier (dropdown case)', () => {
14
+ it('delegates the write to the shared query writer (dropdown case)', () => {
15
15
  const effect = buildUrlWriteBackEffect(
16
16
  'categoryFilter',
17
17
  types.identifier('selectedCategory'),
@@ -22,17 +22,25 @@ describe('URLSearchParamSync.buildUrlWriteBackEffect', () => {
22
22
  // SSR + router-ready guards.
23
23
  expect(code).toContain('if (typeof window === "undefined") return')
24
24
  expect(code).toContain('if (!router.isReady) return')
25
- // Snapshot the current query, then set or delete the bound key.
26
- expect(code).toContain('const __nextQuery =')
27
- expect(code).toContain('...router.query')
28
- expect(code).toContain('if (selectedCategory === "" || selectedCategory == null)')
29
- expect(code).toContain('delete __nextQuery.categoryFilter')
30
- expect(code).toContain('__nextQuery.categoryFilter = String(selectedCategory)')
31
- // Skip-if-equal guard prevents a redundant replace (the loop breaker on the URL side).
32
- expect(code).toContain('if (__nextQuery.categoryFilter === router.query.categoryFilter) return')
33
- expect(code).toContain('shallow: true')
34
- // Deps: the value + router.isReady (so it re-runs once the router hydrates).
25
+
26
+ // ⛔ The effect must NOT build the next query itself. Spreading
27
+ // `router.query` here is what let two controls writing in one flush erase
28
+ // each other's keys — and, through their read-backs, oscillate forever.
29
+ expect(code).not.toContain('__nextQuery')
30
+ expect(code).not.toContain('...router.query')
31
+ expect(code).not.toContain('router.replace')
32
+
33
+ // One key, one call. `undefined` is the writer's "remove this key".
34
+ expect(code).toContain(
35
+ '__tqWriteQueryParam("categoryFilter", selectedCategory === "" || selectedCategory == null ? undefined : selectedCategory)'
36
+ )
37
+
38
+ // ⛔ `router.query` is deliberately NOT a dependency. It was added once as a
39
+ // way to RE-ASSERT a key another writer had dropped, which is precisely the
40
+ // edge that closed the loop; with clobbering fixed at its source there is
41
+ // nothing to re-assert.
35
42
  expect(code).toContain('}, [selectedCategory, router.isReady])')
43
+ expect(code).not.toContain('router.isReady, router.query]')
36
44
  })
37
45
 
38
46
  it('emits the write-back reading a member expression (search debounced-query case)', () => {
@@ -44,16 +52,14 @@ describe('URLSearchParamSync.buildUrlWriteBackEffect', () => {
44
52
  // The value pushed to the URL is read from the combined state object,
45
53
  // not a bare identifier — this is the generalization the search input needs.
46
54
  expect(code).toContain(
47
- 'if (ds_0_state.debouncedQuery === "" || ds_0_state.debouncedQuery == null)'
55
+ '__tqWriteQueryParam("searchKeyword", ds_0_state.debouncedQuery === "" || ds_0_state.debouncedQuery == null ? undefined : ds_0_state.debouncedQuery)'
48
56
  )
49
- expect(code).toContain('__nextQuery.searchKeyword = String(ds_0_state.debouncedQuery)')
50
- expect(code).toContain('if (__nextQuery.searchKeyword === router.query.searchKeyword) return')
51
57
  // Dependency is the debounced member expression, so the URL only updates
52
58
  // after the debounce commits — never on every keystroke.
53
59
  expect(code).toContain('}, [ds_0_state.debouncedQuery, router.isReady])')
54
60
  })
55
61
 
56
- it('uses bracket notation for URL keys that are not valid JS identifiers', () => {
62
+ it('passes a non-identifier URL key through as a plain string argument', () => {
57
63
  const effect = buildUrlWriteBackEffect(
58
64
  'search-keyword',
59
65
  types.identifier('q'),
@@ -61,12 +67,12 @@ describe('URLSearchParamSync.buildUrlWriteBackEffect', () => {
61
67
  )
62
68
  const code = codeOf(effect)
63
69
 
64
- expect(code).toContain('delete __nextQuery["search-keyword"]')
65
- expect(code).toContain('__nextQuery["search-keyword"] = String(q)')
66
- expect(code).not.toContain('__nextQuery.search-keyword')
70
+ // The writer indexes with `next[key]`, so an awkward key needs no bracket
71
+ // gymnastics at the call site any more.
72
+ expect(code).toContain('__tqWriteQueryParam("search-keyword"')
67
73
  })
68
74
 
69
- it('also deletes the key when the value equals a non-empty default (clean canonical URL)', () => {
75
+ it('also removes the key when the value equals a non-empty default (clean canonical URL)', () => {
70
76
  const effect = buildUrlWriteBackEffect(
71
77
  'sortBy',
72
78
  types.identifier('sortBy'),
@@ -75,18 +81,16 @@ describe('URLSearchParamSync.buildUrlWriteBackEffect', () => {
75
81
  )
76
82
  const code = codeOf(effect)
77
83
 
78
- // The default now also routes to the delete branch, so loading the page at
79
- // its default sort never writes a sticky `?sortBy=name-asc`.
80
- expect(code).toContain('if (sortBy === "" || sortBy == null || sortBy === "name-asc")')
81
- expect(code).toContain('delete __nextQuery.sortBy')
82
- expect(code).toContain('__nextQuery.sortBy = String(sortBy)')
84
+ // The default routes to the remove branch, so loading the page at its
85
+ // default sort never writes a sticky `?sortBy=name-asc`.
86
+ expect(code).toContain('sortBy === "" || sortBy == null || sortBy === "name-asc" ? undefined')
83
87
  })
84
88
 
85
- it('omits the default clause when no default is supplied (byte-identical fallback)', () => {
89
+ it('omits the default clause when no default is supplied', () => {
86
90
  const withoutDefault = codeOf(
87
91
  buildUrlWriteBackEffect('sortBy', types.identifier('sortBy'), types.identifier('sortBy'))
88
92
  )
89
- expect(withoutDefault).toContain('if (sortBy === "" || sortBy == null)')
93
+ expect(withoutDefault).toContain('sortBy === "" || sortBy == null ? undefined : sortBy')
90
94
  expect(withoutDefault).not.toContain('=== "name-asc"')
91
95
  })
92
96
  })
@@ -5,10 +5,11 @@ import * as ASTUtils from './utils/ast-utils';
5
5
  import * as StyleUtils from './utils/style-utils';
6
6
  import * as HASTUtils from './utils/hast-utils';
7
7
  import * as URLSearchParamSync from './utils/url-search-param-sync';
8
+ import * as URLQueryWriter from './utils/url-query-writer';
8
9
  import * as RouteUtils from './utils/route-utils';
9
10
  import ParsedASTNode from './utils/parsed-ast';
10
11
  import { createBinaryExpression } from './node-handlers/node-to-jsx/utils';
11
- export { ASTBuilders, StyleBuilders, HASTBuilders, ASTUtils, StyleUtils, HASTUtils, URLSearchParamSync, RouteUtils, ParsedASTNode, createBinaryExpression, };
12
+ export { ASTBuilders, StyleBuilders, HASTBuilders, ASTUtils, StyleUtils, HASTUtils, URLSearchParamSync, URLQueryWriter, RouteUtils, ParsedASTNode, createBinaryExpression, };
12
13
  export { default as createHTMLTemplateSyntax } from './node-handlers/node-to-html';
13
14
  export { default as createJSXSyntax } from './node-handlers/node-to-jsx';
14
15
  export * from './node-handlers/node-to-html/types';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AAExD,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAC/C,OAAO,KAAK,kBAAkB,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,aAAa,MAAM,oBAAoB,CAAA;AAE9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAE1E,OAAO,EACL,WAAW,EACX,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,sBAAsB,GACvB,CAAA;AAED,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AAClF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAExE,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,aAAa,MAAM,2BAA2B,CAAA;AAC1D,OAAO,KAAK,YAAY,MAAM,0BAA0B,CAAA;AAExD,OAAO,KAAK,QAAQ,MAAM,mBAAmB,CAAA;AAC7C,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAC/C,OAAO,KAAK,kBAAkB,MAAM,+BAA+B,CAAA;AACnE,OAAO,KAAK,cAAc,MAAM,0BAA0B,CAAA;AAC1D,OAAO,KAAK,UAAU,MAAM,qBAAqB,CAAA;AACjD,OAAO,aAAa,MAAM,oBAAoB,CAAA;AAE9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAE1E,OAAO,EACL,WAAW,EACX,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,kBAAkB,EAClB,cAAc,EACd,UAAU,EACV,aAAa,EACb,sBAAsB,GACvB,CAAA;AAED,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,8BAA8B,CAAA;AAClF,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAExE,cAAc,oCAAoC,CAAA;AAClD,cAAc,mCAAmC,CAAA"}
package/dist/cjs/index.js CHANGED
@@ -29,7 +29,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
29
29
  return (mod && mod.__esModule) ? mod : { "default": mod };
30
30
  };
31
31
  Object.defineProperty(exports, "__esModule", { value: true });
32
- exports.createJSXSyntax = exports.createHTMLTemplateSyntax = exports.createBinaryExpression = exports.ParsedASTNode = exports.RouteUtils = exports.URLSearchParamSync = exports.HASTUtils = exports.StyleUtils = exports.ASTUtils = exports.HASTBuilders = exports.StyleBuilders = exports.ASTBuilders = void 0;
32
+ exports.createJSXSyntax = exports.createHTMLTemplateSyntax = exports.createBinaryExpression = exports.ParsedASTNode = exports.RouteUtils = exports.URLQueryWriter = exports.URLSearchParamSync = exports.HASTUtils = exports.StyleUtils = exports.ASTUtils = exports.HASTBuilders = exports.StyleBuilders = exports.ASTBuilders = void 0;
33
33
  var ASTBuilders = __importStar(require("./builders/ast-builders"));
34
34
  exports.ASTBuilders = ASTBuilders;
35
35
  var StyleBuilders = __importStar(require("./builders/style-builders"));
@@ -44,6 +44,8 @@ var HASTUtils = __importStar(require("./utils/hast-utils"));
44
44
  exports.HASTUtils = HASTUtils;
45
45
  var URLSearchParamSync = __importStar(require("./utils/url-search-param-sync"));
46
46
  exports.URLSearchParamSync = URLSearchParamSync;
47
+ var URLQueryWriter = __importStar(require("./utils/url-query-writer"));
48
+ exports.URLQueryWriter = URLQueryWriter;
47
49
  var RouteUtils = __importStar(require("./utils/route-utils"));
48
50
  exports.RouteUtils = RouteUtils;
49
51
  var parsed_ast_1 = __importDefault(require("./utils/parsed-ast"));
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mEAAsD;AAcpD,kCAAW;AAbb,uEAA0D;AAcxD,sCAAa;AAbf,qEAAwD;AActD,oCAAY;AAZd,0DAA6C;AAa3C,4BAAQ;AAZV,8DAAiD;AAa/C,gCAAU;AAZZ,4DAA+C;AAa7C,8BAAS;AAZX,gFAAmE;AAajE,gDAAkB;AAZpB,8DAAiD;AAa/C,gCAAU;AAZZ,kEAA8C;AAa5C,wBAbK,oBAAa,CAaL;AAXf,2DAA0E;AAYxE,uGAZO,8BAAsB,OAYP;AAGxB,6DAAkF;AAAzE,yIAAA,OAAO,OAA4B;AAC5C,2DAAwE;AAA/D,+HAAA,OAAO,OAAmB;AAEnC,qEAAkD;AAClD,oEAAiD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mEAAsD;AAepD,kCAAW;AAdb,uEAA0D;AAexD,sCAAa;AAdf,qEAAwD;AAetD,oCAAY;AAbd,0DAA6C;AAc3C,4BAAQ;AAbV,8DAAiD;AAc/C,gCAAU;AAbZ,4DAA+C;AAc7C,8BAAS;AAbX,gFAAmE;AAcjE,gDAAkB;AAbpB,uEAA0D;AAcxD,wCAAc;AAbhB,8DAAiD;AAc/C,gCAAU;AAbZ,kEAA8C;AAc5C,wBAdK,oBAAa,CAcL;AAZf,2DAA0E;AAaxE,uGAbO,8BAAsB,OAaP;AAGxB,6DAAkF;AAAzE,yIAAA,OAAO,OAA4B;AAC5C,2DAAwE;AAA/D,+HAAA,OAAO,OAAmB;AAEnC,qEAAkD;AAClD,oEAAiD"}