@pinegrow/vite-plugin 3.0.73-alpha.0 → 3.0.73-alpha.10

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.
@@ -8,14 +8,44 @@ export interface AstroRuntimeBridgeOptions {
8
8
  export interface AstroElCacheEntry {
9
9
  el: Element
10
10
  framework: 'astro'
11
+ entryKind: 'source-node' | 'component-boundary' | 'page-root'
12
+ treeScopes: {
13
+ pageTree: boolean
14
+ appTree: boolean
15
+ }
11
16
  isAstro: true
17
+ isAstroSourceDomEntry: boolean
18
+ isAstroComponent: boolean
19
+ isAppTreeComponent: boolean
20
+ isAstroPageRoot?: boolean
12
21
  sourceId: string
13
- pgId: string
14
- key: string
22
+ pgId: string | null
23
+ key: string | null
15
24
  localFile: string | null
16
25
  sourceFile: string | null
17
26
  nodeType: string | null
18
27
  name: string
28
+ source: {
29
+ id: string
30
+ file: string | null
31
+ range: {
32
+ start: number | null
33
+ end: number | null
34
+ status: string
35
+ }
36
+ nodeType: string | null
37
+ name: string
38
+ }
39
+ component: {
40
+ file: string
41
+ name: string
42
+ kind: string
43
+ } | null
44
+ owners: Array<{
45
+ kind: string
46
+ file: string
47
+ name?: string
48
+ }>
19
49
  sourceRange: {
20
50
  start: number | null
21
51
  end: number | null
@@ -32,11 +62,53 @@ export interface AstroElCacheEntry {
32
62
  isIsland: false
33
63
  rootEl: null
34
64
  firstEl: Element
35
- lastEl: Element
36
- instance: null
65
+ lastEl: Element | null
66
+ instance: {
67
+ uid: string
68
+ isMounted: boolean
69
+ isUnmounted: boolean
70
+ type: {
71
+ __name?: string
72
+ __file?: string | null
73
+ }
74
+ props: Record<string, unknown>
75
+ attrs: Record<string, unknown>
76
+ slots: Record<string, unknown>
77
+ subTree: {
78
+ el: Element
79
+ }
80
+ appContext: unknown
81
+ }
37
82
  vnode: null
38
83
  }
39
84
 
85
+ export type AstroComponentEntry = AstroElCacheEntry & {
86
+ entryKind: 'component-boundary' | 'page-root'
87
+ treeScopes: {
88
+ pageTree: false
89
+ appTree: true
90
+ }
91
+ isAstroSourceDomEntry: false
92
+ isAstroComponent: true
93
+ isAppTreeComponent: true
94
+ pgId: null
95
+ key: null
96
+ localFile: string
97
+ sourceFile: string
98
+ nodeType: 'component-file'
99
+ component: {
100
+ file: string
101
+ name: string
102
+ kind: string
103
+ }
104
+ }
105
+
106
+ export function createAstroComponentEntries(input: {
107
+ entries: AstroElCacheEntry[]
108
+ manifest: unknown
109
+ root?: Document | Element
110
+ }): AstroComponentEntry[]
111
+
40
112
  export function createAstroElCacheEntry(input: {
41
113
  element: Element
42
114
  manifest: unknown
@@ -1,5 +1,49 @@
1
1
  const defaultMarkerAttribute = 'data-pg-source-id'
2
+ const pinegrowMarkerAttribute = 'data-pg-id'
2
3
  const astroFrameworkKey = 'astro'
4
+ const astroSourceIdPrefix = 'pgastro-'
5
+
6
+ const createFallbackComputed = getter => ({
7
+ get value() {
8
+ return getter()
9
+ },
10
+ })
11
+
12
+ const createFallbackRef = value => ({ value })
13
+
14
+ const readWatchSource = source => {
15
+ if (typeof source === 'function') {
16
+ return source()
17
+ }
18
+
19
+ return source?.value
20
+ }
21
+
22
+ const createFallbackWatch = (source, callback, options = {}) => {
23
+ if (options.immediate && typeof callback === 'function') {
24
+ callback(readWatchSource(source), undefined)
25
+ }
26
+
27
+ return () => {}
28
+ }
29
+
30
+ const createAstroSyntheticInstance = (node, element) => ({
31
+ uid: `astro:${node.id}`,
32
+ isMounted: true,
33
+ isUnmounted: false,
34
+ parent: null,
35
+ type: {
36
+ __name: node.name || 'AstroElement',
37
+ __file: null,
38
+ },
39
+ props: {},
40
+ attrs: {},
41
+ slots: {},
42
+ subTree: {
43
+ el: element,
44
+ },
45
+ appContext: null,
46
+ })
3
47
 
4
48
  const getDefaultWindow = () => {
5
49
  if (typeof window !== 'undefined') {
@@ -16,6 +60,13 @@ const isMapLike = value =>
16
60
  typeof value.delete === 'function' &&
17
61
  typeof value.entries === 'function'
18
62
 
63
+ const createReactiveMap = (pinegrow, value) => {
64
+ const map = isMapLike(value) ? value : new Map()
65
+ const reactiveFromContext = pinegrow?.reactiveFromContext
66
+
67
+ return typeof reactiveFromContext === 'function' ? reactiveFromContext(map) : map
68
+ }
69
+
19
70
  const getMarkerAttribute = (manifest, options = {}) =>
20
71
  options.markerAttribute || manifest?.marker?.attribute || defaultMarkerAttribute
21
72
 
@@ -23,6 +74,57 @@ const getManifestSourceKey = manifest => manifest?.sourceFile || manifest?.id ||
23
74
 
24
75
  const normalizeElCacheEntries = entries => Array.isArray(entries) ? entries : []
25
76
 
77
+ const normalizePathLike = value => `${value || ''}`.replace(/\\/g, '/')
78
+
79
+ const getBasename = value => {
80
+ if (!value) {
81
+ return ''
82
+ }
83
+
84
+ return normalizePathLike(value).split('/').pop() || ''
85
+ }
86
+
87
+ const isAstroPageSourceFile = sourceFile =>
88
+ /(^|\/)src\/pages\/.+\.astro$/i.test(normalizePathLike(sourceFile))
89
+
90
+ const getRootElement = root => {
91
+ if (!root) {
92
+ return null
93
+ }
94
+
95
+ if (root.documentElement) {
96
+ return root.documentElement
97
+ }
98
+
99
+ if (root.body) {
100
+ return root.body
101
+ }
102
+
103
+ if (root.firstElementChild) {
104
+ return root.firstElementChild
105
+ }
106
+
107
+ return root.nodeType === 1 ? root : null
108
+ }
109
+
110
+ const createAstroComponentSyntheticInstance = (manifest, componentId, element) => ({
111
+ uid: componentId,
112
+ isMounted: true,
113
+ isUnmounted: false,
114
+ parent: null,
115
+ type: {
116
+ __name: getBasename(manifest?.sourceFile) || 'AstroComponent',
117
+ __file: manifest?.sourceFile || null,
118
+ },
119
+ props: {},
120
+ attrs: {},
121
+ slots: {},
122
+ subTree: {
123
+ el: element,
124
+ },
125
+ appContext: null,
126
+ })
127
+
26
128
  const createNodeIndex = manifest => {
27
129
  const index = new Map()
28
130
 
@@ -51,7 +153,42 @@ const getElementMarkerId = (element, markerAttribute) => {
51
153
  return element.getAttribute(markerAttribute)
52
154
  }
53
155
 
54
- const createAstroElCacheEntry = ({ element, manifest, node }) => {
156
+ const canOverwritePgId = currentValue =>
157
+ !currentValue || currentValue.startsWith(astroSourceIdPrefix)
158
+
159
+ const mirrorAstroSourceIdToPgId = (element, sourceId, options = {}) => {
160
+ if (
161
+ options.mirrorPgId === false ||
162
+ !sourceId ||
163
+ !element ||
164
+ typeof element.getAttribute !== 'function' ||
165
+ typeof element.setAttribute !== 'function'
166
+ ) {
167
+ return false
168
+ }
169
+
170
+ const currentPgId = element.getAttribute(pinegrowMarkerAttribute)
171
+
172
+ if (currentPgId === sourceId) {
173
+ return true
174
+ }
175
+
176
+ if (!canOverwritePgId(currentPgId)) {
177
+ return false
178
+ }
179
+
180
+ element.setAttribute(pinegrowMarkerAttribute, sourceId)
181
+
182
+ return true
183
+ }
184
+
185
+ const createAstroElCacheEntry = ({
186
+ element,
187
+ manifest,
188
+ markerAttribute = defaultMarkerAttribute,
189
+ node,
190
+ mirroredPgId = false,
191
+ }) => {
55
192
  const sourceRange = {
56
193
  start: node.sourceStart ?? null,
57
194
  end: node.sourceEnd ?? null,
@@ -61,19 +198,41 @@ const createAstroElCacheEntry = ({ element, manifest, node }) => {
61
198
  return {
62
199
  el: element,
63
200
  framework: astroFrameworkKey,
201
+ entryKind: 'source-node',
202
+ treeScopes: {
203
+ pageTree: true,
204
+ appTree: false,
205
+ },
64
206
  isAstro: true,
207
+ isAstroSourceDomEntry: true,
208
+ isAstroComponent: false,
209
+ isAppTreeComponent: false,
65
210
  sourceId: node.id,
66
211
  pgId: node.id,
67
212
  key: node.id,
68
- localFile: manifest.sourceFile || null,
213
+ localFile: null,
69
214
  sourceFile: manifest.sourceFile || null,
70
215
  nodeType: node.type || null,
71
216
  name: node.name || '',
217
+ source: {
218
+ id: node.id,
219
+ file: manifest.sourceFile || null,
220
+ range: sourceRange,
221
+ nodeType: node.type || null,
222
+ name: node.name || '',
223
+ },
224
+ component: null,
225
+ owners: [],
72
226
  sourceRange,
73
227
  sourceStart: sourceRange.start,
74
228
  sourceEnd: sourceRange.end,
75
229
  sourceRangeStatus: sourceRange.status,
76
- marker: node.marker || null,
230
+ marker: {
231
+ ...(node.marker || {}),
232
+ liveAttribute: markerAttribute,
233
+ pinegrowAttribute: pinegrowMarkerAttribute,
234
+ mirroredPgId,
235
+ },
77
236
  editability: node.editability || null,
78
237
  attributes: node.attributes || [],
79
238
  isFragment: false,
@@ -82,11 +241,99 @@ const createAstroElCacheEntry = ({ element, manifest, node }) => {
82
241
  rootEl: null,
83
242
  firstEl: element,
84
243
  lastEl: element,
85
- instance: null,
244
+ instance: createAstroSyntheticInstance(node, element),
86
245
  vnode: null,
87
246
  }
88
247
  }
89
248
 
249
+ const createAstroComponentEntry = ({ entries, manifest, root }) => {
250
+ const sourceFile = manifest?.sourceFile
251
+ const rootElement = getRootElement(root)
252
+ const isPageFile = isAstroPageSourceFile(sourceFile)
253
+ const isPageRoot = isPageFile && rootElement
254
+
255
+ if (!sourceFile || (!entries.length && !isPageRoot)) {
256
+ return null
257
+ }
258
+
259
+ const firstEntry = entries[0]
260
+ const lastEntry = entries[entries.length - 1]
261
+ const componentId = `astro-component:${sourceFile}`
262
+ const firstEl = isPageRoot ? rootElement : firstEntry.firstEl || firstEntry.el
263
+ const lastEl = isPageRoot ? null : lastEntry.lastEl || lastEntry.el
264
+ const componentName = getBasename(sourceFile)
265
+ const entryKind = isPageRoot ? 'page-root' : 'component-boundary'
266
+
267
+ return {
268
+ el: firstEl,
269
+ framework: astroFrameworkKey,
270
+ entryKind,
271
+ treeScopes: {
272
+ pageTree: false,
273
+ appTree: true,
274
+ },
275
+ isAstro: true,
276
+ isAstroSourceDomEntry: false,
277
+ isAstroComponent: true,
278
+ isAppTreeComponent: true,
279
+ isAstroPageRoot: Boolean(isPageRoot),
280
+ sourceId: componentId,
281
+ pgId: null,
282
+ key: null,
283
+ localFile: sourceFile,
284
+ sourceFile,
285
+ nodeType: 'component-file',
286
+ name: componentName,
287
+ source: {
288
+ id: componentId,
289
+ file: sourceFile,
290
+ range: {
291
+ start: null,
292
+ end: null,
293
+ status: 'component-file',
294
+ },
295
+ nodeType: 'component-file',
296
+ name: componentName,
297
+ },
298
+ component: {
299
+ file: sourceFile,
300
+ name: componentName,
301
+ kind: isPageFile ? 'page' : 'component',
302
+ },
303
+ owners: [],
304
+ sourceRange: {
305
+ start: null,
306
+ end: null,
307
+ status: 'component-file',
308
+ },
309
+ sourceStart: null,
310
+ sourceEnd: null,
311
+ sourceRangeStatus: 'component-file',
312
+ marker: null,
313
+ editability: {
314
+ mode: 'inspect',
315
+ operations: ['select', 'open-source-file'],
316
+ reasons: ['astro-component-file'],
317
+ },
318
+ attributes: [],
319
+ state: Array.isArray(manifest.state) ? manifest.state : [],
320
+ isFragment: false,
321
+ isRootFragment: false,
322
+ isIsland: false,
323
+ rootEl: null,
324
+ firstEl,
325
+ lastEl,
326
+ instance: createAstroComponentSyntheticInstance(manifest, componentId, firstEl),
327
+ vnode: null,
328
+ }
329
+ }
330
+
331
+ const createAstroComponentEntries = ({ entries, manifest, root }) => {
332
+ const componentEntry = createAstroComponentEntry({ entries, manifest, root })
333
+
334
+ return componentEntry ? [componentEntry] : []
335
+ }
336
+
90
337
  const scanAstroSourceDomMarkers = (root, manifest, options = {}) => {
91
338
  const markerAttribute = getMarkerAttribute(manifest, options)
92
339
  const entries = []
@@ -97,6 +344,7 @@ const scanAstroSourceDomMarkers = (root, manifest, options = {}) => {
97
344
  status: 'unavailable',
98
345
  markerAttribute,
99
346
  entries,
347
+ componentEntries: [],
100
348
  missing,
101
349
  reason: manifest?.reason || 'Astro source manifest is unavailable.',
102
350
  }
@@ -107,6 +355,7 @@ const scanAstroSourceDomMarkers = (root, manifest, options = {}) => {
107
355
  status: 'unavailable',
108
356
  markerAttribute,
109
357
  entries,
358
+ componentEntries: [],
110
359
  missing,
111
360
  reason: 'A DOM root with querySelectorAll() is required.',
112
361
  }
@@ -119,17 +368,28 @@ const scanAstroSourceDomMarkers = (root, manifest, options = {}) => {
119
368
  const node = nodeIndex.get(sourceId)
120
369
 
121
370
  if (!node) {
122
- missing.push({ element, sourceId })
371
+ if (options.reportMissingMarkers) {
372
+ missing.push({ element, sourceId })
373
+ }
123
374
  return
124
375
  }
125
376
 
126
- entries.push(createAstroElCacheEntry({ element, manifest, node }))
377
+ const mirroredPgId = mirrorAstroSourceIdToPgId(element, sourceId, options)
378
+
379
+ entries.push(createAstroElCacheEntry({
380
+ element,
381
+ manifest,
382
+ markerAttribute,
383
+ node,
384
+ mirroredPgId,
385
+ }))
127
386
  })
128
387
 
129
388
  return {
130
389
  status: 'ready',
131
390
  markerAttribute,
132
391
  entries,
392
+ componentEntries: createAstroComponentEntries({ entries, manifest, root }),
133
393
  missing,
134
394
  }
135
395
  }
@@ -143,17 +403,32 @@ const ensurePinegrowAstroBridge = (win = getDefaultWindow()) => {
143
403
  win.pinegrow = {}
144
404
  }
145
405
 
146
- if (!isMapLike(win.pinegrow.elCache)) {
147
- win.pinegrow.elCache = new Map()
406
+ if (typeof win.pinegrow.reactiveFromContext !== 'function') {
407
+ win.pinegrow.reactiveFromContext = value => value
148
408
  }
149
409
 
410
+ if (typeof win.pinegrow.refFromContext !== 'function') {
411
+ win.pinegrow.refFromContext = createFallbackRef
412
+ }
413
+
414
+ if (typeof win.pinegrow.computedFromContext !== 'function') {
415
+ win.pinegrow.computedFromContext = createFallbackComputed
416
+ }
417
+
418
+ if (typeof win.pinegrow.watchFromContext !== 'function') {
419
+ win.pinegrow.watchFromContext = createFallbackWatch
420
+ }
421
+
422
+ win.pinegrow.elCache = createReactiveMap(win.pinegrow, win.pinegrow.elCache)
423
+
150
424
  if (!win.pinegrow.astro) {
151
425
  win.pinegrow.astro = {}
152
426
  }
153
427
 
154
- if (!isMapLike(win.pinegrow.astro.sourceManifests)) {
155
- win.pinegrow.astro.sourceManifests = new Map()
156
- }
428
+ win.pinegrow.astro.sourceManifests = createReactiveMap(
429
+ win.pinegrow,
430
+ win.pinegrow.astro.sourceManifests
431
+ )
157
432
 
158
433
  return win.pinegrow
159
434
  }
@@ -232,7 +507,9 @@ const refreshAstroElCache = (manifest, options = {}) => {
232
507
  : removeAstroEntriesForManifest(pinegrow.elCache, manifest)
233
508
  const updatedElements = new Set(removal.elements)
234
509
 
235
- scan.entries.forEach(entry => {
510
+ const cacheEntries = [...scan.entries, ...(scan.componentEntries || [])]
511
+
512
+ cacheEntries.forEach(entry => {
236
513
  upsertAstroEntry(pinegrow.elCache, entry)
237
514
  updatedElements.add(entry.el)
238
515
  })
@@ -251,7 +528,7 @@ const refreshAstroElCache = (manifest, options = {}) => {
251
528
 
252
529
  return {
253
530
  ...scan,
254
- cached: scan.entries.length,
531
+ cached: cacheEntries.length,
255
532
  removed: removal.removed,
256
533
  }
257
534
  }
@@ -267,6 +544,7 @@ const createAstroRuntimeBridge = (manifest, options = {}) => ({
267
544
  })
268
545
 
269
546
  export {
547
+ createAstroComponentEntries,
270
548
  createAstroElCacheEntry,
271
549
  createAstroRuntimeBridge,
272
550
  ensurePinegrowAstroBridge,