aiplang 2.7.1 → 2.7.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.
- package/bin/aiplang.js +30 -22
- package/package.json +1 -1
- package/server/server.js +1 -1
package/bin/aiplang.js
CHANGED
|
@@ -5,7 +5,7 @@ const fs = require('fs')
|
|
|
5
5
|
const path = require('path')
|
|
6
6
|
const http = require('http')
|
|
7
7
|
|
|
8
|
-
const VERSION = '2.7.
|
|
8
|
+
const VERSION = '2.7.3'
|
|
9
9
|
const RUNTIME_DIR = path.join(__dirname, '..', 'runtime')
|
|
10
10
|
const cmd = process.argv[2]
|
|
11
11
|
const args = process.argv.slice(3)
|
|
@@ -615,23 +615,28 @@ function parseBlock(line) {
|
|
|
615
615
|
}
|
|
616
616
|
|
|
617
617
|
// ── table ───────────────────────────────────────────────────
|
|
618
|
-
if(line.startsWith('table ')) {
|
|
618
|
+
if(line.startsWith('table ') || line.startsWith('table{')) {
|
|
619
619
|
const idx=line.indexOf('{');if(idx===-1) return null
|
|
620
|
-
const
|
|
620
|
+
const start=line.startsWith('table{')?6:6
|
|
621
|
+
const binding=line.slice(start,idx).trim().replace(/^@/,'@')
|
|
621
622
|
const content=line.slice(idx+1,line.lastIndexOf('}')).trim()
|
|
622
623
|
const em=content.match(/edit\s+(PUT|PATCH)\s+(\S+)/), dm=content.match(/delete\s+(?:DELETE\s+)?(\S+)/)
|
|
623
624
|
const clean=content.replace(/edit\s+(PUT|PATCH)\s+\S+/g,'').replace(/delete\s+(?:DELETE\s+)?\S+/g,'')
|
|
624
|
-
|
|
625
|
+
const cols=parseCols(clean)
|
|
626
|
+
return{kind:'table',binding,cols:Array.isArray(cols)?cols:[],empty:parseEmpty(clean),editPath:em?.[2]||null,editMethod:em?.[1]||'PUT',deletePath:dm?.[1]||null,deleteKey:'id',extraClass,animate}
|
|
625
627
|
}
|
|
626
628
|
|
|
627
629
|
// ── form ────────────────────────────────────────────────────
|
|
628
|
-
if(line.startsWith('form ')) {
|
|
630
|
+
if(line.startsWith('form ') || line.startsWith('form{')) {
|
|
629
631
|
const bi=line.indexOf('{');if(bi===-1) return null
|
|
630
|
-
let head=line.slice(
|
|
632
|
+
let head=line.slice(line.startsWith('form{')?4:5,bi).trim()
|
|
633
|
+
const content=line.slice(bi+1,line.lastIndexOf('}')).trim()
|
|
631
634
|
let action=''; const ai=head.indexOf('=>')
|
|
632
635
|
if(ai!==-1){action=head.slice(ai+2).trim();head=head.slice(0,ai).trim()}
|
|
633
|
-
const
|
|
634
|
-
|
|
636
|
+
const parts=head.trim().split(/\s+/)
|
|
637
|
+
const method=parts[0]&&['GET','POST','PUT','PATCH','DELETE'].includes(parts[0].toUpperCase())?parts[0].toUpperCase():'POST'
|
|
638
|
+
const bpath=parts[method===parts[0].toUpperCase()?1:0]||''
|
|
639
|
+
return{kind:'form',method,bpath,action,fields:parseFields(content)||[],extraClass,animate}
|
|
635
640
|
}
|
|
636
641
|
|
|
637
642
|
// ── pricing ─────────────────────────────────────────────────
|
|
@@ -724,7 +729,7 @@ function applyMods(html, b) {
|
|
|
724
729
|
|
|
725
730
|
function renderPage(page, allPages) {
|
|
726
731
|
const needsJS=page.queries.length>0||page.blocks.some(b=>['table','list','form','if','btn','select','faq'].includes(b.kind))
|
|
727
|
-
const body=page.blocks.map(b=>applyMods(renderBlock(b,page),b)).join('')
|
|
732
|
+
const body=page.blocks.map(b=>{try{return applyMods(renderBlock(b,page),b)}catch(e){console.error('[aiplang] Block render error:',b.kind,e.message);return ''}}).join('')
|
|
728
733
|
const config=needsJS?JSON.stringify({id:page.id,theme:page.theme,routes:allPages.map(p=>p.route),state:page.state,queries:page.queries}):''
|
|
729
734
|
const hydrate=needsJS?`\n<script>window.__AIPLANG_PAGE__=${config};</script>\n<script src="./aiplang-hydrate.js" defer></script>`:''
|
|
730
735
|
const customVars=page.customTheme?genCustomThemeVars(page.customTheme):''
|
|
@@ -797,7 +802,7 @@ function rStats(b) {
|
|
|
797
802
|
}
|
|
798
803
|
|
|
799
804
|
function rRow(b) {
|
|
800
|
-
const cards=b.items.map(item=>{
|
|
805
|
+
const cards=(b.items||[]).map(item=>{
|
|
801
806
|
const inner=item.map((f,fi)=>{
|
|
802
807
|
if(f.isImg) return`<img src="${esc(f.src)}" class="fx-card-img" alt="" loading="lazy">`
|
|
803
808
|
if(f.isLink) return`<a href="${esc(f.path)}" class="fx-card-link">${esc(f.label)} →</a>`
|
|
@@ -822,7 +827,7 @@ function rSect(b) {
|
|
|
822
827
|
|
|
823
828
|
function rFoot(b) {
|
|
824
829
|
let inner=''
|
|
825
|
-
for(const item of b.items) for(const f of item){
|
|
830
|
+
for(const item of (b.items||[])) for(const f of item){
|
|
826
831
|
if(f.isLink) inner+=`<a href="${esc(f.path)}" class="fx-footer-link">${esc(f.label)}</a>`
|
|
827
832
|
else inner+=`<p class="fx-footer-text">${esc(f.text)}</p>`
|
|
828
833
|
}
|
|
@@ -830,24 +835,27 @@ function rFoot(b) {
|
|
|
830
835
|
}
|
|
831
836
|
|
|
832
837
|
function rTable(b) {
|
|
833
|
-
const
|
|
834
|
-
const
|
|
835
|
-
const
|
|
838
|
+
const cols=Array.isArray(b.cols)?b.cols:[]
|
|
839
|
+
const ths=cols.map(c=>`<th class="fx-th">${esc(c.label)}</th>`).join('')
|
|
840
|
+
const keys=JSON.stringify(cols.map(c=>c.key))
|
|
841
|
+
const cm=JSON.stringify(cols.map(c=>({label:c.label,key:c.key})))
|
|
836
842
|
const ea=b.editPath?` data-fx-edit="${esc(b.editPath)}" data-fx-edit-method="${esc(b.editMethod)}"`:''
|
|
837
843
|
const da=b.deletePath?` data-fx-delete="${esc(b.deletePath)}"`:''
|
|
838
844
|
const at=(b.editPath||b.deletePath)?'<th class="fx-th fx-th-actions">Actions</th>':''
|
|
839
|
-
const span=
|
|
845
|
+
const span=cols.length+((b.editPath||b.deletePath)?1:0)
|
|
840
846
|
return `<div class="fx-table-wrap"><table class="fx-table" data-fx-table="${esc(b.binding)}" data-fx-cols='${keys}' data-fx-col-map='${cm}'${ea}${da}><thead><tr>${ths}${at}</tr></thead><tbody class="fx-tbody"><tr><td colspan="${span}" class="fx-td-empty">${esc(b.empty)}</td></tr></tbody></table></div>\n`
|
|
841
847
|
}
|
|
842
848
|
|
|
843
849
|
function rForm(b) {
|
|
844
|
-
const fields=b.fields.map(f=>{
|
|
850
|
+
const fields=(b.fields||[]).map(f=>{
|
|
851
|
+
if(!f) return ''
|
|
845
852
|
const inp=f.type==='select'
|
|
846
853
|
?`<select class="fx-input" name="${esc(f.name)}"><option value="">Select...</option></select>`
|
|
847
|
-
:`<input class="fx-input" type="${esc(f.type)}" name="${esc(f.name)}" placeholder="${esc(f.placeholder)}">`
|
|
854
|
+
:`<input class="fx-input" type="${esc(f.type||'text')}" name="${esc(f.name)}" placeholder="${esc(f.placeholder)}">`
|
|
848
855
|
return`<div class="fx-field"><label class="fx-label">${esc(f.label)}</label>${inp}</div>`
|
|
849
856
|
}).join('')
|
|
850
|
-
|
|
857
|
+
const label=b.submitLabel||'Submit'
|
|
858
|
+
return `<div class="fx-form-wrap"><form class="fx-form" data-fx-form="${esc(b.bpath)}" data-fx-method="${esc(b.method)}" data-fx-action="${esc(b.action)}">${fields}<div class="fx-form-msg"></div><button type="submit" class="fx-btn">${esc(label)}</button></form></div>\n`
|
|
851
859
|
}
|
|
852
860
|
|
|
853
861
|
function rBtn(b) {
|
|
@@ -857,12 +865,12 @@ function rBtn(b) {
|
|
|
857
865
|
}
|
|
858
866
|
|
|
859
867
|
function rSelectBlock(b) {
|
|
860
|
-
const opts=b.options.map(o=>`<option value="${esc(o)}">${esc(o)}</option>`).join('')
|
|
868
|
+
const opts=(b.options||[]).map(o=>`<option value="${esc(o)}">${esc(o)}</option>`).join('')
|
|
861
869
|
return `<div class="fx-select-wrap"><select class="fx-input fx-select-block" data-fx-model="${esc(b.binding)}">${opts}</select></div>\n`
|
|
862
870
|
}
|
|
863
871
|
|
|
864
872
|
function rPricing(b) {
|
|
865
|
-
const cards=b.plans.map((p,i)=>{
|
|
873
|
+
const cards=(b.plans||[]).map((p,i)=>{
|
|
866
874
|
let lh='#',ll='Get started'
|
|
867
875
|
if(p.linkRaw){const m=p.linkRaw.match(/\/([^:]+):(.+)/);if(m){lh='/'+m[1];ll=m[2]}}
|
|
868
876
|
const f=i===1?' fx-pricing-featured':''
|
|
@@ -873,7 +881,7 @@ function rPricing(b) {
|
|
|
873
881
|
}
|
|
874
882
|
|
|
875
883
|
function rFaq(b) {
|
|
876
|
-
const items=b.items.map(i=>`<div class="fx-faq-item" onclick="this.classList.toggle('open')"><div class="fx-faq-q">${esc(i.q)}<span class="fx-faq-arrow">▸</span></div><div class="fx-faq-a">${esc(i.a)}</div></div>`).join('')
|
|
884
|
+
const items=(b.items||[]).map(i=>`<div class="fx-faq-item" onclick="this.classList.toggle('open')"><div class="fx-faq-q">${esc(i.q)}<span class="fx-faq-arrow">▸</span></div><div class="fx-faq-a">${esc(i.a)}</div></div>`).join('')
|
|
877
885
|
return `<section class="fx-sect"><div class="fx-faq">${items}</div></section>\n`
|
|
878
886
|
}
|
|
879
887
|
|
|
@@ -883,7 +891,7 @@ function rTestimonial(b) {
|
|
|
883
891
|
}
|
|
884
892
|
|
|
885
893
|
function rGallery(b) {
|
|
886
|
-
const imgs=b.imgs.map(src=>`<div class="fx-gallery-item"><img src="${esc(src)}" alt="" loading="lazy"></div>`).join('')
|
|
894
|
+
const imgs=(b.imgs||[]).map(src=>`<div class="fx-gallery-item"><img src="${esc(src)}" alt="" loading="lazy"></div>`).join('')
|
|
887
895
|
return `<div class="fx-gallery">${imgs}</div>\n`
|
|
888
896
|
}
|
|
889
897
|
|
package/package.json
CHANGED
package/server/server.js
CHANGED
|
@@ -1435,7 +1435,7 @@ async function startServer(aipFile, port = 3000) {
|
|
|
1435
1435
|
|
|
1436
1436
|
// Health
|
|
1437
1437
|
srv.addRoute('GET', '/health', (req, res) => res.json(200, {
|
|
1438
|
-
status:'ok', version:'2.7.
|
|
1438
|
+
status:'ok', version:'2.7.3',
|
|
1439
1439
|
models: app.models.map(m=>m.name),
|
|
1440
1440
|
routes: app.apis.length, pages: app.pages.length,
|
|
1441
1441
|
admin: app.admin?.prefix || null,
|