pawa-ssr 1.3.30 → 1.4.1

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.
package/index.d.ts ADDED
@@ -0,0 +1,66 @@
1
+ import { HTMLElement } from 'linkedom';
2
+
3
+ /**
4
+ * Core rendering function that processes PawaElements/HTMLElements and writes to a stream.
5
+ */
6
+ export function render(el: any, contexts?: object, stream?: (s: string) => void): Promise<void>;
7
+
8
+ export interface StartAppResult {
9
+ element: any;
10
+ toString: () => Promise<string>;
11
+ head: string;
12
+ }
13
+
14
+ /**
15
+ * Initializes and renders the application for standard SSR.
16
+ */
17
+ export function startApp(
18
+ html: string,
19
+ context?: object,
20
+ development?: boolean
21
+ ): Promise<StartAppResult>;
22
+
23
+ /**
24
+ * Initializes and renders the application using Node.js streams for performance and Suspense support.
25
+ */
26
+ export function startStreamApp(
27
+ html: string,
28
+ context: object,
29
+ stream: (s: string) => void,
30
+ options: { templateStart: string; templateEnd: string }
31
+ ): Promise<void>;
32
+
33
+ /**
34
+ * Adds custom directives that should be treated as part of the PawaJS directive set.
35
+ */
36
+ export function addToPartlyDirective(...partly: string[]): void;
37
+
38
+ /**
39
+ * Returns an array of all reserved server attributes.
40
+ */
41
+ export function getAllServerAttrArray(): string[];
42
+
43
+ /**
44
+ * Returns the set of registered Pawa attributes.
45
+ */
46
+ export function getPawaAttributes(): Set<string>;
47
+
48
+ /**
49
+ * Checks if the application is running in development mode.
50
+ */
51
+ export function getDevelopment(): boolean | undefined;
52
+
53
+ /**
54
+ * Configures the server-side hooks for PawaJS.
55
+ */
56
+ export const pawaForServer: (config: {
57
+ useContext: (context: { id: string }) => any;
58
+ useInnerContext: () => any;
59
+ useInsert: (obj?: object) => void;
60
+ setContext: () => { id: string; setValue: (context: object) => void };
61
+ $state: <T>(initialValue: T | (() => T)) => T;
62
+ accessChild: () => void;
63
+ useServer: () => { setServerData: (data: object) => void, getServerData: () => object } | undefined;
64
+ useAsync: () => { $async: <R>(callback: () => R) => R, onSuspense: (html: string) => void } | undefined;
65
+ forwardProps: (props?: object) => void;
66
+ }) => void;
package/index.js CHANGED
@@ -243,92 +243,6 @@ const setPawaAttribute=(...attr)=>{
243
243
  }
244
244
  setPawaAttribute('if','else','else-if','for-each','case','switch','s-default','for-key','key')
245
245
  export const getPawaAttributes=()=>pawaAttributes
246
- /**
247
- * @typedef {{startsWith:string,fullName:string,plugin:(el:HTMLElement | PawaElement,attr:object)=>void}} AttriPlugin
248
- */
249
- /**
250
- * @typedef {{
251
- * attribute?:{register:Array<AttriPlugin>},
252
- * component?:{
253
- * beforeCall?:(stateContext:PawaComponent,app:object)=>void,
254
- * afterCall?:(stateContext:PawaComponent,el:HTMLElement)=>void
255
- * },
256
- * renderSystem?:{
257
- * beforePawa?:(el:HTMLElement,context:object)=>void,
258
- * afterPawa?:(el:PawaElement)=>void,
259
- * beforeChildRender?:(el:PawaElement)=>void
260
- * }
261
- * }} PluginObject
262
- */
263
- /**
264
- * @param {Array<()=>PluginObject>} func
265
- */
266
- export const PluginSystem=(...func)=>{
267
- func.forEach(fn=>{
268
- /**
269
- * @type {PluginObject}
270
- */
271
- if (typeof fn !== 'function') {
272
- console.warn('plugin must be a function that returns the plugin objects')
273
- return
274
- }
275
- const getPlugin=fn()
276
- // attributes plugin or extension
277
-
278
- if (getPlugin?.attribute) {
279
- getPlugin.attribute.register.forEach(attrPlugins =>{
280
- if (attrPlugins.fullName && attrPlugins.startsWith) {
281
- console.warn('Either Plugins FullName or startsWith. you are not required to use to of does plugin registers at this same entry.')
282
- return
283
- }
284
- if (attrPlugins?.fullName) {
285
- if (pawaAttributes.has(attrPlugins.fullName) ) {
286
- console.warn(`attribute plugin already exist ${attrPlugins.fullName}`)
287
- return
288
- }
289
- pawaAttributes.add(attrPlugins.fullName)
290
- fullNamePlugin.add(attrPlugins.fullName)
291
- externalPlugin[attrPlugins.fullName]=attrPlugins?.plugin
292
- }else if (attrPlugins?.startsWith) {
293
- if (pawaAttributes.has(attrPlugins.startsWith) ) {
294
- console.warn(`attribute plugin already exist ${attrPlugins.startsWith}`)
295
- return
296
- }
297
- pawaAttributes.add(attrPlugins.startsWith)
298
- startsWithSet.add(attrPlugins.startsWith)
299
- externalPlugin[attrPlugins.startsWith]=attrPlugins?.plugin
300
- }
301
- })
302
- }
303
- if (getPlugin?.component) {
304
- if (getPlugin.component?.beforeCall && typeof getPlugin.component?.beforeCall === 'function') {
305
- compoBeforeCall.add(getPlugin.component.beforeCall)
306
- }
307
- if (getPlugin.component?.afterCall && typeof getPlugin.component?.afterCall === 'function') {
308
- compoAfterCall.add(getPlugin.component.afterCall)
309
- }
310
- }
311
- if (getPlugin?.renderSystem) {
312
- if (getPlugin.renderSystem?.beforePawa && typeof getPlugin.renderSystem?.beforePawa === 'function') {
313
- renderBeforePawa.add(getPlugin.renderSystem?.beforePawa)
314
- }
315
- if (getPlugin.renderSystem?.afterPawa && typeof getPlugin.renderSystem?.afterPawa === 'function') {
316
- renderAfterPawa.add(getPlugin.renderSystem?.afterPawa)
317
- }
318
- if (getPlugin.renderSystem?.beforeChildRender && typeof getPlugin.renderSystem?.beforeChildRender === 'function') {
319
- renderBeforeChild.add(getPlugin.renderSystem?.beforeChildRender)
320
- }
321
- }
322
- })
323
- }
324
-
325
- export const useValidateComponent=(component,object)=>{
326
- if (typeof component === 'function' ) {
327
- if(component.name){
328
- component.validateProps=object
329
- }
330
- }
331
- }
332
246
 
333
247
  /**
334
248
  * @typedef {{
@@ -484,12 +398,13 @@ appContext.component._prop={children,...el._props,...slots}
484
398
  }else{
485
399
  Object.assign(restProps,el._restProps)
486
400
  }
487
- const getAsChild=()=>{
488
- const asChild=div.firstElementChild
489
- if (splitAndAdd(asChild?.tagName|| '') === 'ASCHILD') {
490
- const getChildren=asChild.firstElementChild
401
+ const getAsChild=(divs)=>{
402
+ const divFirst=divs.firstElementChild
403
+ if (el._aschild) {
404
+ divs.innerHTML=children
405
+ const getChildren=divs.firstElementChild
491
406
  if (getChildren === null) return
492
- Array.from(asChild.attributes).forEach(attr=>{
407
+ Array.from(divFirst.attributes).forEach(attr=>{
493
408
  if (getChildren.hasAttribute(attr.name)) {
494
409
  let attrName=getChildren.getAttribute(attr.name)
495
410
  attrName=attr.value +' '+attrName
@@ -497,12 +412,10 @@ appContext.component._prop={children,...el._props,...slots}
497
412
  }else{
498
413
  getChildren.setAttribute(attr.name, attr.value)
499
414
  }
500
- })
501
- asChild.remove()
502
- div.appendChild(getChildren)
415
+ })
503
416
  }
504
- }
505
- getAsChild()
417
+ }
418
+ getAsChild(div)
506
419
  const findElement=div.querySelector('[--]') || div.querySelector('[r-]')
507
420
  if (findElement) {
508
421
  for (const [key,value] of Object.entries(restProps)) {
@@ -716,11 +629,12 @@ appContext.component._prop={children,...el._props,...slots}
716
629
  Object.assign(restProps,el._restProps)
717
630
  }
718
631
  const getAsChild=(divs)=>{
719
- const asChild=divs.firstElementChild
720
- if (splitAndAdd(asChild?.tagName|| '') === 'ASCHILD') {
721
- const getChildren=asChild.firstElementChild
632
+ const divFirst=divs.firstElementChild
633
+ if (el._aschild) {
634
+ divs.innerHTML=children
635
+ const getChildren=divs.firstElementChild
722
636
  if (getChildren === null) return
723
- Array.from(asChild.attributes).forEach(attr=>{
637
+ Array.from(divFirst.attributes).forEach(attr=>{
724
638
  if (getChildren.hasAttribute(attr.name)) {
725
639
  let attrName=getChildren.getAttribute(attr.name)
726
640
  attrName=attr.value +' '+attrName
@@ -728,9 +642,7 @@ appContext.component._prop={children,...el._props,...slots}
728
642
  }else{
729
643
  getChildren.setAttribute(attr.name, attr.value)
730
644
  }
731
- })
732
- asChild.remove()
733
- divs.appendChild(getChildren)
645
+ })
734
646
  }
735
647
  }
736
648
  if (isBoundary) {
@@ -931,7 +843,11 @@ const attributeHandler =async (el, attr) => {
931
843
  if (el._componentName) {
932
844
  return
933
845
  }
934
- el._replaceResumeAttr(attr.name,`c-at-${attr.name}`,attr.value)
846
+
847
+ const isAtAttr = attr.name.startsWith('@');
848
+ const targetName = isAtAttr ? attr.name.slice(1) : attr.name;
849
+
850
+ el._replaceResumeAttr(attr.name, `c-at-${targetName}`, attr.value);
935
851
  const currentHtmlString = el.outerHTML;
936
852
  const removableAttributes = new Set();
937
853
  removableAttributes.add('disabled');
@@ -945,18 +861,18 @@ const attributeHandler =async (el, attr) => {
945
861
  const func =el._evaluateExpr(
946
862
  expression,
947
863
  el._context,
948
- `from text interpolation @{} - ${expression} at ${currentHtmlString} attribute ${attr.name}`
864
+ `from text interpolation @{} - ${expression} at ${currentHtmlString} attribute ${targetName}`
949
865
  );
950
866
  value = value.replace(fullMatch, String(func));
951
867
  });
952
- if (removableAttributes.has(attr.name)) {
868
+ if (removableAttributes.has(targetName)) {
953
869
  if (value) {
954
- el.setAttribute(attr.name, '');
870
+ el.setAttribute(targetName, '');
955
871
  } else {
956
- el.removeAttribute(attr.name);
872
+ el.removeAttribute(targetName);
957
873
  }
958
874
  } else {
959
- el.setAttribute(attr.name, value);
875
+ el.setAttribute(targetName, value);
960
876
  }
961
877
  } catch (error) {
962
878
  console.log(error.message, error.stack);
@@ -1072,12 +988,12 @@ export const render =async (el, contexts = {},stream) => {
1072
988
  for(const attr of attributes){
1073
989
  if (directives[attr.name]) {
1074
990
  await directives[attr.name](el,attr,stream)
1075
- }else if(attr.value.includes('@{') && !isAcomponent){
991
+ }else if((attr.value.includes('@{') || attr.name.startsWith('@')) && !isAcomponent){
1076
992
  await attributeHandler(el,attr)
1077
993
  }else if (attr.name.startsWith('state-')) {
1078
994
  directives['state-'](el,attr)
1079
995
  }
1080
- else if(fullNamePlugin.has(attr.name)) {
996
+ else if(fullNamePlugin.has(attr.name) && !el._componentName) {
1081
997
  if(externalPlugin[attr.name]){
1082
998
  const plugin= externalPlugin[attr.name]
1083
999
  try{
@@ -1090,9 +1006,9 @@ export const render =async (el, contexts = {},stream) => {
1090
1006
  console.warn(error.message,error.stack)
1091
1007
  }
1092
1008
  }
1093
- }else if(startAttribute){
1009
+ }else if(startAttribute ){
1094
1010
  const name=startObject[attr.name]
1095
- if(externalPlugin[name]){
1011
+ if(externalPlugin[name] && !el._componentName){
1096
1012
  const plugin= externalPlugin[name]
1097
1013
  try{
1098
1014
  if (typeof plugin !== 'function') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pawa-ssr",
3
- "version": "1.3.30",
3
+ "version": "1.4.1",
4
4
  "type": "module",
5
5
  "description": "pawajs ssr libary",
6
6
  "main": "index.js",
@@ -24,7 +24,9 @@
24
24
  },
25
25
  "homepage": "https://github.com/Allisboy/pawajs-ssr#readme",
26
26
  "dependencies": {
27
- "linkedom": "^0.18.11",
28
- "pawajs": "^1.5.2"
27
+ "linkedom": "^0.18.11"
28
+ },
29
+ "peerDependencies": {
30
+ "pawajs": "^2.0.0"
29
31
  }
30
32
  }
package/pawaElement.js CHANGED
@@ -19,6 +19,7 @@ class PawaElement {
19
19
  * @type{PawaElement|HTMLElement}
20
20
  */
21
21
  this._el=element
22
+ this._aschild=false
22
23
  this._slots=document.createDocumentFragment()
23
24
  this._context=context
24
25
  this._avoidPawaRender=element.hasAttribute('s-pawa-avoid')
@@ -166,6 +167,7 @@ class PawaElement {
166
167
 
167
168
  getComponent(){
168
169
  if (components.has(splitAndAdd(this._el.tagName.toUpperCase())) && !this._client || this._lazy) {
170
+ if(this._el.hasAttribute('data-prevent:c'))return
169
171
  this._componentName=splitAndAdd(this._el.tagName.toUpperCase())
170
172
  const fakeCompo=()=>true
171
173
  this._component=new PawaComponent(components.get(splitAndAdd(this._el.tagName.toUpperCase())),fakeCompo)
@@ -194,12 +196,13 @@ class PawaElement {
194
196
  //set Component props
195
197
  setProps(){
196
198
  if (this._componentName) {
197
- const allServerAttr=getPawaAttributes()
199
+ const allServerAttr=['if','else','else-if','key','for-each','case','switch','s-default']
198
200
  this._el.attributes.forEach(attr=>{
199
- if(!allServerAttr.has(attr.name)){
200
- if (attr.name === 'svg') {
201
- return
202
- }
201
+ if (attr.name ==='aschild' || attr.name === 'as-child' || attr.name === ':as-child') {
202
+ this._aschild=true
203
+ return
204
+ }
205
+ if(!allServerAttr.includes(attr.name)){
203
206
  if ( !attr.name.startsWith(':')) {
204
207
  if( attr.name.startsWith('c-')||attr.name.startsWith('pawa-') || attr.name.startsWith('p:c') || attr.name.startsWith('state-')) return
205
208
  let name=''
@@ -228,7 +231,7 @@ class PawaElement {
228
231
 
229
232
  });
230
233
  return value
231
- }else if( attr.name.startsWith('on-') || attr.name.startsWith('out-') || attr.name === 'ref'){
234
+ }else if( attr.name.startsWith('on-') || attr.name.startsWith('out-')){
232
235
  const res=this.evaluateExpr(`(e)=>{
233
236
  ${attr.value}
234
237
  }`, this._context,`evaluating props with template operators at ${attr.name} - ${attr.value} : ${this._template}`)
@@ -281,16 +284,11 @@ class PawaElement {
281
284
  evaluateExpr(expr, context = {},error){
282
285
  try {
283
286
  const keys = Object.keys(context);
284
- // Create a cache key based on the expression and the available context keys
285
- // We sort keys to ensure consistent cache hits regardless of key order
286
- const cacheKey = expr + '|||' + keys.sort().join(',');
287
-
288
- let func = expressionCache.get(cacheKey);
287
+ let func
289
288
  if (!func) {
290
289
  func = new Function(...keys, `
291
290
  const require=null
292
291
  return ${expr}`);
293
- expressionCache.set(cacheKey, func);
294
292
  }
295
293
 
296
294
  const values = keys.map((key) => context[key]);
package/test/App.js CHANGED
@@ -1,4 +1,8 @@
1
+ import { useInnerContext } from "pawajs"
2
+
1
3
  export const App=({children})=>{
4
+ const context=useInnerContext()
5
+ console.log(context)
2
6
  return `<div class="p-4">
3
7
  <h1 class="text-2xl font-bold mb-4">Hello, World!</h1>
4
8
  <p class="text-gray-700">This is a test component for PawaJS.</p>
package/test/index.js CHANGED
@@ -1,13 +1,24 @@
1
- import {useValidateComponent, RegisterComponent,useContext,useInsert,setContext} from 'pawajs'
2
- import {startApp} from '../index.js'
1
+ import {useValidateComponent, RegisterComponent,useContext,useInsert,setContext,forwardProps} from 'pawajs'
2
+ import {startApp,startStreamApp} from '../index.js'
3
3
  RegisterComponent.lazy(
4
4
  'App',()=>import('./App.js'),
5
5
  'Check',()=>import('./check.js'),
6
6
  'Check2',()=>import('./check.js'),
7
7
  )
8
-
8
+ const Dinput=({className,...props})=>{
9
+ forwardProps(props)
10
+ const classActive=()=>[className?.() || '','py-2 text-blue'].join(' ')
11
+ useInsert({classActive})
12
+ return `
13
+ <input class="@{classActive()}" -- />
14
+ `
15
+ }
16
+ RegisterComponent(Dinput)
9
17
  const app=`
10
18
  <div>
19
+ <dinput type="file" aschild>
20
+ <div>aschild</div>
21
+ </dinput>
11
22
  <app>
12
23
  <check></check>
13
24
  <check-2></check-2>
@@ -17,5 +28,11 @@ const app=`
17
28
  </div>
18
29
  </div>
19
30
  `
20
- const {toString}=await startApp(app)
21
- console.log(await toString());
31
+ // const {toString}=await startApp(app)
32
+ // console.log(await toString());
33
+ let strings=''
34
+ const stream=(string)=>strings+=string
35
+
36
+ await startStreamApp(app,{url:'/'},stream,{templateEnd:'</body>',templateStart:'<body>'})
37
+ console.log(strings);
38
+