@useavalon/avalon 0.1.89 → 0.1.90
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/dist/src/build/integration-bundler-plugin.d.ts +1 -1
- package/dist/src/build/integration-detection-plugin.d.ts +1 -1
- package/dist/src/build/integration-detection-plugin.js +1 -1
- package/dist/src/build/integration-resolver-plugin.d.ts +1 -1
- package/dist/src/build/island-code-splitting.d.ts +1 -1
- package/dist/src/build/island-manifest.d.ts +2 -2
- package/dist/src/build/island-manifest.js +1 -1
- package/dist/src/build/island-types-generator.js +4 -4
- package/dist/src/build/mdx-island-transform.js +1 -1
- package/dist/src/build/mdx-plugin.d.ts +2 -2
- package/dist/src/build/prop-extractors/index.d.ts +3 -3
- package/dist/src/build/prop-extractors/index.js +1 -1
- package/dist/src/build/prop-extractors/lit.js +1 -1
- package/dist/src/build/prop-extractors/svelte.js +1 -1
- package/dist/src/build/sidecar-file-manager.js +1 -1
- package/dist/src/client/adapters/index.d.ts +1 -1
- package/dist/src/client/adapters/index.js +1 -1
- package/dist/src/client/css-hmr-handler.d.ts +2 -2
- package/dist/src/client/framework-adapter.d.ts +2 -2
- package/dist/src/client/hmr-coordinator.d.ts +6 -6
- package/dist/src/client/types/framework-runtime.d.ts +54 -55
- package/dist/src/client/types/vite-hmr.d.ts +35 -35
- package/dist/src/client/types/vite-virtual-modules.d.ts +56 -28
- package/dist/src/core/components/component-analyzer.d.ts +3 -3
- package/dist/src/core/components/component-analyzer.js +1 -1
- package/dist/src/core/components/component-detection.d.ts +8 -8
- package/dist/src/core/components/component-detection.js +1 -1
- package/dist/src/core/components/enhanced-framework-detector.d.ts +2 -2
- package/dist/src/core/components/enhanced-framework-detector.js +1 -1
- package/dist/src/core/components/framework-registry.d.ts +1 -1
- package/dist/src/core/integrations/index.d.ts +1 -1
- package/dist/src/core/integrations/index.js +1 -1
- package/dist/src/core/integrations/registry.js +1 -1
- package/dist/src/core/layout/enhanced-layout-resolver.d.ts +8 -8
- package/dist/src/core/layout/enhanced-layout-resolver.js +1 -1
- package/dist/src/core/layout/layout-cache-manager.d.ts +1 -1
- package/dist/src/core/layout/layout-composer.d.ts +2 -2
- package/dist/src/core/layout/layout-composer.js +1 -1
- package/dist/src/core/layout/layout-data-loader.d.ts +2 -2
- package/dist/src/core/layout/layout-discovery.d.ts +2 -2
- package/dist/src/core/layout/layout-discovery.js +1 -1
- package/dist/src/core/layout/layout-matcher.d.ts +1 -1
- package/dist/src/core/layout/layout-matcher.js +1 -1
- package/dist/src/core/layout/layout-types.d.ts +3 -3
- package/dist/src/islands/component-analysis.d.ts +4 -4
- package/dist/src/islands/component-analysis.js +1 -1
- package/dist/src/islands/css-utils.js +1 -1
- package/dist/src/islands/discovery/index.d.ts +9 -9
- package/dist/src/islands/discovery/index.js +1 -1
- package/dist/src/islands/discovery/registry.d.ts +1 -1
- package/dist/src/islands/discovery/resolver.d.ts +1 -1
- package/dist/src/islands/discovery/resolver.js +2 -2
- package/dist/src/islands/discovery/scanner.d.ts +1 -1
- package/dist/src/islands/discovery/scanner.js +1 -1
- package/dist/src/islands/discovery/validator.d.ts +1 -1
- package/dist/src/islands/discovery/validator.js +9 -9
- package/dist/src/islands/discovery/watcher.d.ts +1 -1
- package/dist/src/islands/discovery/watcher.js +1 -1
- package/dist/src/islands/framework-detection.d.ts +3 -3
- package/dist/src/islands/framework-detection.js +1 -1
- package/dist/src/islands/island.js +1 -1
- package/dist/src/islands/universal-head-collector.d.ts +2 -2
- package/dist/src/middleware/discovery.d.ts +1 -1
- package/dist/src/middleware/discovery.js +1 -1
- package/dist/src/middleware/executor.d.ts +2 -2
- package/dist/src/middleware/index.d.ts +3 -3
- package/dist/src/middleware/index.js +1 -1
- package/dist/src/middleware/types.d.ts +2 -2
- package/dist/src/nitro/error-handler.d.ts +2 -2
- package/dist/src/nitro/error-handler.js +2 -2
- package/dist/src/nitro/index.d.ts +8 -8
- package/dist/src/nitro/index.js +1 -1
- package/dist/src/nitro/island-manifest.d.ts +1 -1
- package/dist/src/nitro/island-manifest.js +1 -1
- package/dist/src/nitro/middleware-adapter.d.ts +2 -2
- package/dist/src/nitro/types.d.ts +4 -4
- package/dist/src/render/isolated-ssr-renderer.d.ts +2 -2
- package/dist/src/render/isolated-ssr-renderer.js +1 -1
- package/dist/src/render/ssr.d.ts +5 -5
- package/dist/src/render/ssr.js +4 -4
- package/dist/src/schemas/api.d.ts +1 -1
- package/dist/src/schemas/core.d.ts +1 -1
- package/dist/src/schemas/index.d.ts +8 -8
- package/dist/src/schemas/index.js +1 -1
- package/dist/src/schemas/routing/index.d.ts +1 -1
- package/dist/src/schemas/routing/index.js +1 -1
- package/dist/src/schemas/routing.d.ts +4 -4
- package/dist/src/schemas/routing.js +1 -1
- package/dist/src/types/image.d.ts +38 -38
- package/dist/src/types/island-jsx.d.ts +16 -16
- package/dist/src/types/mdx.d.ts +2 -2
- package/dist/src/types/routing.d.ts +7 -7
- package/dist/src/types/routing.js +1 -1
- package/dist/src/types/virtual-modules.d.ts +1 -1
- package/dist/src/types/vite-env.d.ts +1 -1
- package/dist/src/vite-plugin/auto-discover.js +1 -1
- package/dist/src/vite-plugin/config.d.ts +1 -1
- package/dist/src/vite-plugin/image-optimization.d.ts +2 -2
- package/dist/src/vite-plugin/image-optimization.js +1 -1
- package/dist/src/vite-plugin/island-sidecar-plugin.js +1 -1
- package/dist/src/vite-plugin/module-discovery.js +1 -1
- package/dist/src/vite-plugin/plugin.d.ts +2 -2
- package/dist/src/vite-plugin/plugin.js +1 -1
- package/dist/src/vite-plugin/types.d.ts +1 -2
- package/package.json +3 -2
- package/dist/src/client/main-slim.js +0 -1
- package/dist/src/client/strategies.js +0 -1
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module provides a convenient interface for analyzing components
|
|
5
5
|
* and making hydration decisions in the SSR system.
|
|
6
6
|
*/
|
|
7
|
-
import { type ComponentAnalysis, type
|
|
7
|
+
import { type ComponentAnalysis, type ComponentMetadata, type DetectionResult } from "./component-detection.ts";
|
|
8
8
|
export interface AnalyzerOptions {
|
|
9
9
|
forceSSROnly?: boolean;
|
|
10
10
|
detectScripts?: boolean;
|
|
@@ -35,7 +35,7 @@ export declare function shouldHydrate(filePath: string, options?: AnalyzerOption
|
|
|
35
35
|
/**
|
|
36
36
|
* Get component framework type
|
|
37
37
|
*/
|
|
38
|
-
export declare function getComponentFramework(filePath: string): Promise<ComponentAnalysis[
|
|
38
|
+
export declare function getComponentFramework(filePath: string): Promise<ComponentAnalysis["framework"]>;
|
|
39
39
|
/**
|
|
40
40
|
* Generate summary statistics for a batch of components
|
|
41
41
|
*/
|
|
@@ -45,4 +45,4 @@ export declare function generateAnalysisSummary(reports: Map<string, AnalysisRep
|
|
|
45
45
|
byStrategy: Record<string, number>;
|
|
46
46
|
withWarnings: number;
|
|
47
47
|
};
|
|
48
|
-
export type { ComponentAnalysis, DetectionResult,
|
|
48
|
+
export type { ComponentAnalysis, ComponentMetadata, DetectionResult, } from "./component-detection.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{analyzeComponent as e,
|
|
1
|
+
import{analyzeComponent as e,createComponentMetadata as t,shouldHydrateComponent as n}from"./component-detection.js";export async function analyzeComponentFile(r,i={}){try{let{readFile:a}=await import(`node:fs/promises`),o=await a(r,`utf-8`),s=e(r,o),l=n(s,i),u=t(r,o,s);return i.logDecisions&&c(r,s,l),{metadata:u,decision:l,analysis:s}}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Failed to analyze component ${r}: ${t}`)}}export function analyzeComponentContent(r,i,a={}){let o=e(r,i),s=n(o,a),l=t(r,i,o);return a.logDecisions&&c(r,o,s),{metadata:l,decision:s,analysis:o}}export async function analyzeComponents(e,t={}){let n=new Map;for(let i of e)try{let e=await analyzeComponentFile(i,t);n.set(i,e)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`Failed to analyze ${i}:`,t)}return n}export async function shouldHydrate(e,t={}){try{return(await analyzeComponentFile(e,t)).decision.shouldHydrate}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`Error checking hydration for ${e}:`,n),!0}}export async function getComponentFramework(e){try{return(await analyzeComponentFile(e)).analysis.framework}catch(t){let n=t instanceof Error?t.message:String(t);return console.error(`Error detecting framework for ${e}:`,n),`unknown`}}function c(e,t,n){let r=t.framework.toUpperCase(),i=n.shouldHydrate?`HYDRATE`:`SSR-ONLY`;console.log(`[Component Analysis] ${e}`),console.log(` Framework: ${r}`),console.log(` Has Script: ${t.hasScript}`),console.log(` Has Hydrate Function: ${t.hasHydrateFunction}`),console.log(` Strategy: ${i}`),console.log(` Reason: ${n.reason}`),n.warnings&&n.warnings.length>0&&(console.log(` Warnings:`),n.warnings.forEach(e=>console.log(` - ${e}`))),console.log(``)}export function generateAnalysisSummary(e){let t={total:e.size,byFramework:{},byStrategy:{},withWarnings:0};for(let[,n]of e){let e=n.analysis.framework;t.byFramework[e]=(t.byFramework[e]||0)+1;let r=n.decision.shouldHydrate?`hydrate`:`ssr-only`;t.byStrategy[r]=(t.byStrategy[r]||0)+1,n.decision.warnings&&n.decision.warnings.length>0&&t.withWarnings++}return t}
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
export interface ComponentAnalysis {
|
|
8
8
|
hasScript: boolean;
|
|
9
9
|
hasHydrateFunction: boolean;
|
|
10
|
-
framework:
|
|
11
|
-
recommendedStrategy:
|
|
10
|
+
framework: "vue" | "svelte" | "solid" | "preact" | "react" | "lit" | "qwik" | "unknown";
|
|
11
|
+
recommendedStrategy: "hydrate" | "ssr-only";
|
|
12
12
|
}
|
|
13
13
|
export interface DetectionResult {
|
|
14
14
|
shouldHydrate: boolean;
|
|
@@ -17,24 +17,24 @@ export interface DetectionResult {
|
|
|
17
17
|
}
|
|
18
18
|
export interface ComponentMetadata {
|
|
19
19
|
path: string;
|
|
20
|
-
framework:
|
|
20
|
+
framework: "vue" | "svelte" | "solid" | "preact" | "react" | "lit" | "qwik";
|
|
21
21
|
hasScript: boolean;
|
|
22
22
|
hasHydrateFunction: boolean;
|
|
23
|
-
renderStrategy:
|
|
24
|
-
detectionConfidence:
|
|
23
|
+
renderStrategy: "hydrate" | "ssr-only";
|
|
24
|
+
detectionConfidence: "high" | "medium" | "low";
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
27
|
* Detects the framework type based on file extension and content
|
|
28
28
|
*/
|
|
29
|
-
export declare function detectFramework(filePath: string, content: string): ComponentAnalysis[
|
|
29
|
+
export declare function detectFramework(filePath: string, content: string): ComponentAnalysis["framework"];
|
|
30
30
|
/**
|
|
31
31
|
* Detects if a component has script sections
|
|
32
32
|
*/
|
|
33
|
-
export declare function hasScriptSection(content: string, framework: ComponentAnalysis[
|
|
33
|
+
export declare function hasScriptSection(content: string, framework: ComponentAnalysis["framework"]): boolean;
|
|
34
34
|
/**
|
|
35
35
|
* Detects if a component has hydration functions
|
|
36
36
|
*/
|
|
37
|
-
export declare function hasHydrateFunction(content: string, framework: ComponentAnalysis[
|
|
37
|
+
export declare function hasHydrateFunction(content: string, framework: ComponentAnalysis["framework"]): boolean;
|
|
38
38
|
/**
|
|
39
39
|
* Extracts script content from Vue components
|
|
40
40
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const e={vue:{fileExtensions:[`.vue`],scriptTags:[`<script>`,`<script setup>`,`<script lang="ts">`,`<script setup lang="ts">`],hydratePatterns:[`hydrate`,`mount`,`createApp`,`Vue.createApp`],imports:[`vue`,`@vue/`,`vue/`]},svelte:{fileExtensions:[`.svelte`],scriptTags:[`<script>`,`<script lang="ts">`,`<script context="module">`],hydratePatterns:[`hydrate`,`mount`,`$:`,`onMount`],imports:[`svelte`,`svelte/`]},solid:{fileExtensions:[`.tsx`,`.jsx`,`.solid.tsx`,`.solid.jsx`],scriptTags:[],hydratePatterns:[`hydrate`,`render`,`createSignal`,`createEffect`],imports:[`solid-js`,`solid-js/web`]},preact:{fileExtensions:[`.tsx`,`.jsx`,`.preact.tsx`,`.preact.jsx`],scriptTags:[],hydratePatterns:[`hydrate`,`render`],imports:[`preact`,`preact/hooks`]},react:{fileExtensions:[`.tsx`,`.jsx`,`.react.tsx`,`.react.jsx`],scriptTags:[],hydratePatterns:[`hydrate`,`render`],imports:[`react`,`react-dom`]},lit:{fileExtensions:[`.ts`,`.js`],scriptTags:[],hydratePatterns:[`LitElement`,`customElement`,`@customElement`],imports:[`lit`,`lit-element`,`lit/`]},qwik:{fileExtensions:[`.tsx`,`.jsx`,`.qwik.tsx`,`.qwik.jsx`],scriptTags:[],hydratePatterns:[`component$`,`useSignal`,`useStore`,`useTask$`,`useVisibleTask$`],imports:[`@builder.io/qwik`,`@builder.io/qwik/`]}};function t(e){return e.includes(`.solid.`)?`solid`:e.includes(`.preact.`)?`preact`:e.includes(`.react.`)?`react`:e.includes(`.qwik.`)?`qwik`:null}function n(e,t){return e.endsWith(`.vue`)?`vue`:e.endsWith(`.svelte`)?`svelte`:(e.endsWith(`.ts`)||e.endsWith(`.js`))&&(t.includes(`lit`)||t.includes(`LitElement`)||t.includes(`@customElement`))?`lit`:e.endsWith(`.tsx`)||e.endsWith(`.jsx`)?r(t):null}function r(e){return e.includes(`solid-js`)||e.includes(`from "solid-js"`)||e.includes(`from 'solid-js'`)?`solid`:e.includes(`@builder.io/qwik`)||e.includes(`from "@builder.io/qwik"`)||e.includes(`from '@builder.io/qwik'`)?`qwik`:e.includes(`preact`)||e.includes(`from "preact"`)||e.includes(`from 'preact'`)?`preact`:e.includes(`react`)&&!e.includes(`preact`)?`react`:`preact`}export function detectFramework(e,r){return t(e)??n(e,r)??i(r)}function i(t){for(let[n,r]of Object.entries(e))if(r.imports.some(e=>t.includes(e)))return n;return`unknown`}export function hasScriptSection(e,t){switch(t){case`vue`:return/<script[^>]*>/i.test(e);case`svelte`:return e.includes(`<script>`)||e.includes(`<script `)||e.includes(`<script
|
|
2
|
-
`)||e.includes(`<script `);case`solid`:case`preact`:case`react`:case`qwik`:return e.includes(`function`)||e.includes(`=>`)||e.includes(`const`)||e.includes(`let`);case`lit`:return e.includes(`class`)||e.includes(`LitElement`)||e.includes(`@customElement`);default:return e.includes(`<script>`)||e.includes(`function`)||e.includes(`=>`)}}export function hasHydrateFunction(t,n){if(!e[n])return!1;if([`export function hydrate`,`export const hydrate`,`function hydrate(`,`const hydrate =`,`let hydrate =`,`var hydrate =`].some(e=>t.toLowerCase().includes(e.toLowerCase())))return!0;switch(n){case`vue`:return t.includes(`createApp`)&&t.includes(`mount`);case`svelte`:return t.includes(`import`)&&t.includes(`hydrate`)&&(t.includes(`svelte`)||t.includes(`hydrate(`));case`solid`:return t.includes(`hydrate`)&&t.includes(`solid-js`)||t.includes(`render`)&&t.includes(`solid-js/web`);case`preact`:return t.includes(`hydrate`)&&t.includes(`preact`)||t.includes(`render`)&&t.includes(`preact`);case`react`:return t.includes(`hydrate`)&&t.includes(`react`)||t.includes(`render`)&&t.includes(`react-dom`);case`qwik`:return t.includes(`component$`)||t.includes(`@builder.io/qwik`);default:return!1}}export function extractVueScript(e){return o(e)}export function extractSvelteScript(e){return o(e)}function o(e){let t=/<script[^>]*>([\s\S]*?)<\/script>/gi,n=[]
|
|
2
|
+
`)||e.includes(`<script `);case`solid`:case`preact`:case`react`:case`qwik`:return e.includes(`function`)||e.includes(`=>`)||e.includes(`const`)||e.includes(`let`);case`lit`:return e.includes(`class`)||e.includes(`LitElement`)||e.includes(`@customElement`);default:return e.includes(`<script>`)||e.includes(`function`)||e.includes(`=>`)}}export function hasHydrateFunction(t,n){if(!e[n])return!1;if([`export function hydrate`,`export const hydrate`,`function hydrate(`,`const hydrate =`,`let hydrate =`,`var hydrate =`].some(e=>t.toLowerCase().includes(e.toLowerCase())))return!0;switch(n){case`vue`:return t.includes(`createApp`)&&t.includes(`mount`);case`svelte`:return t.includes(`import`)&&t.includes(`hydrate`)&&(t.includes(`svelte`)||t.includes(`hydrate(`));case`solid`:return t.includes(`hydrate`)&&t.includes(`solid-js`)||t.includes(`render`)&&t.includes(`solid-js/web`);case`preact`:return t.includes(`hydrate`)&&t.includes(`preact`)||t.includes(`render`)&&t.includes(`preact`);case`react`:return t.includes(`hydrate`)&&t.includes(`react`)||t.includes(`render`)&&t.includes(`react-dom`);case`qwik`:return t.includes(`component$`)||t.includes(`@builder.io/qwik`);default:return!1}}export function extractVueScript(e){return o(e)}export function extractSvelteScript(e){return o(e)}function o(e){let t=/<script[^>]*>([\s\S]*?)<\/script>/gi,n=[];for(let r=t.exec(e);r!==null;r=t.exec(e))n.push(r[0]);return n.join(`
|
|
3
3
|
`)}const s=/^\s*return\s*\(/;function c(e){return e.split(`
|
|
4
4
|
`).filter(e=>{let t=e.trim();return!t.startsWith(`<`)&&!t.startsWith(`</`)&&!s.exec(t)}).join(`
|
|
5
5
|
`)}export function extractSolidScript(e){return c(e)}export function extractPreactScript(e){return c(e)}export function extractReactScript(e){return c(e)}export function analyzeComponent(e,t){let n=detectFramework(e,t),r=hasScriptSection(t,n),i=r?hasHydrateFunction(t,n):!1,a;if(r)switch(n){case`svelte`:a=l(t,i);break;case`solid`:case`preact`:case`react`:a=`hydrate`;break;case`qwik`:a=`hydrate`;break;case`vue`:a=i?`hydrate`:`ssr-only`;break;default:a=i?`hydrate`:`ssr-only`;break}else a=`ssr-only`;return{hasScript:r,hasHydrateFunction:i,framework:n,recommendedStrategy:a}}function l(e,t){if(t)return`hydrate`;let n=`on:.onclick.onchange.oninput.onsubmit.onkeydown.onkeyup.onmousedown.onmouseup.bind:.$:.$state.$derived.$effect.$props.onMount.onDestroy.beforeUpdate.afterUpdate.tick.writable.readable.derived.get(.set(.update(.subscribe(`.split(`.`).some(t=>e.includes(t));return[`export let`].some(t=>e.includes(t))&&!n?`ssr-only`:`hydrate`}const u={solid:`SolidJS component detected - uses integration system`,preact:`preact component with script content - likely needs hydration`,react:`react component with script content - likely needs hydration`,svelte:`Svelte component with script section - uses Svelte hydration system`,vue:`Vue component with script section - uses Vue integration system`,lit:`Lit component detected - Web Components require client-side registration`,qwik:`Qwik component detected - uses resumability instead of hydration`};export function shouldHydrateComponent(e,t={}){if(t.forceSSROnly)return{shouldHydrate:!1,reason:`Explicitly configured for SSR-only rendering`};if(t.detectScripts===!1)return{shouldHydrate:!0,reason:`Script detection disabled, defaulting to hydration`};if(!e.hasScript)return{shouldHydrate:!1,reason:`No script section detected, using SSR-only rendering`};let n=u[e.framework];return n?{shouldHydrate:!0,reason:n}:e.hasHydrateFunction?{shouldHydrate:!0,reason:`Component has script section with explicit hydration functions`}:{shouldHydrate:!1,reason:`Component has script section but no explicit hydrate function, using SSR-only`,warnings:[`Component has script section but no clear hydrate function detected`]}}export function createComponentMetadata(e,t,n){let r=`medium`;return n.framework!==`unknown`&&n.hasScript&&n.hasHydrateFunction||n.framework!==`unknown`&&!n.hasScript?r=`high`:n.framework===`unknown`&&(r=`low`),{path:e,framework:n.framework===`unknown`?`vue`:n.framework,hasScript:n.hasScript,hasHydrateFunction:n.hasHydrateFunction,renderStrategy:n.recommendedStrategy,detectionConfidence:r}}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* component frameworks and prevent cross-framework conflicts.
|
|
7
7
|
*/
|
|
8
8
|
export interface FrameworkDetectionResult {
|
|
9
|
-
framework:
|
|
10
|
-
confidence:
|
|
9
|
+
framework: "preact" | "solid" | "vue" | "svelte" | "react" | "lit" | "qwik" | "unknown";
|
|
10
|
+
confidence: "high" | "medium" | "low";
|
|
11
11
|
evidence: string[];
|
|
12
12
|
warnings: string[];
|
|
13
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export class EnhancedFrameworkDetector{frameworkRegistry;constructor(e){this.frameworkRegistry=new Map;let t=e||this.getDefaultFrameworkConfigs();Object.entries(t).forEach(([e,t])=>{this.frameworkRegistry.set(e,t)})}detectFramework(e,t){let n=this.extractDetectionCriteria(e,t),r=[],i=[];if(e.includes(`.solid.`))return r.push(`Explicit Solid naming convention (.solid.tsx/.solid.jsx)`),{framework:`solid`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.preact.`))return r.push(`Explicit Preact naming convention (.preact.tsx/.preact.jsx)`),{framework:`preact`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.react.`))return r.push(`Explicit React naming convention (.react.tsx/.react.jsx)`),{framework:`react`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.lit.`))return r.push(`Explicit Lit naming convention (.lit.ts/.lit.js)`),{framework:`lit`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.qwik.`))return r.push(`Explicit Qwik naming convention (.qwik.tsx/.qwik.jsx)`),{framework:`qwik`,confidence:`high`,evidence:r,warnings:i};let a=new Map;for(let[e,t]of this.frameworkRegistry){let i=this.calculateFrameworkScore(n,t,r);a.set(e,i)}let o=Array.from(a.entries()).sort(([,e],[,t])=>t-e),[s,c]=o[0]||[`unknown`,0],[l,u]=o[1]||[`unknown`,0],d;return c>=3&&c-u>=2?d=`high`:c>=2?d=`medium`:(d=`low`,i.push(`Framework detection has low confidence - consider adding explicit JSX import source or use naming convention (.solid.tsx, .preact.tsx)`)),c===u&&c>0&&(i.push(`Ambiguous detection between ${s} and ${l} - consider using naming convention`),d=`low`),{framework:c>0?s:`unknown`,confidence:d,evidence:r,warnings:i}}extractDetectionCriteria(e,t){return{fileExtension:this.getFileExtension(e),jsxImportSource:this.parseJSXImportSource(t),imports:this.extractImportStatements(t),content:t}}calculateFrameworkScore(e,t,n){let r=0;e.jsxImportSource&&t.jsxImportSources.includes(e.jsxImportSource)&&(r+=3,n.push(`JSX import source: @jsxImportSource ${e.jsxImportSource}`));for(let i of t.detectionPatterns.imports)e.imports.some(e=>i.test(e))&&(r+=2,n.push(`Framework import detected: ${i.source}`));for(let i of t.detectionPatterns.content)i.test(e.content)&&(r+=1,n.push(`Framework-specific content pattern: ${i.source}`));return t.fileExtensions.includes(e.fileExtension)&&(r+=.5,n.push(`File extension: ${e.fileExtension}`)),r}parseJSXImportSource(e){let t=/@jsxImportSource\s+([^\s*]+)/.exec(e);if(t)return t[1]}extractImportStatements(e){let t=[],n=/from\s+['"]([^'"]+)['"]/g,r=/import\s+['"]([^'"]+)['"]/g,i=/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,a;for(
|
|
1
|
+
export class EnhancedFrameworkDetector{frameworkRegistry;constructor(e){this.frameworkRegistry=new Map;let t=e||this.getDefaultFrameworkConfigs();Object.entries(t).forEach(([e,t])=>{this.frameworkRegistry.set(e,t)})}detectFramework(e,t){let n=this.extractDetectionCriteria(e,t),r=[],i=[];if(e.includes(`.solid.`))return r.push(`Explicit Solid naming convention (.solid.tsx/.solid.jsx)`),{framework:`solid`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.preact.`))return r.push(`Explicit Preact naming convention (.preact.tsx/.preact.jsx)`),{framework:`preact`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.react.`))return r.push(`Explicit React naming convention (.react.tsx/.react.jsx)`),{framework:`react`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.lit.`))return r.push(`Explicit Lit naming convention (.lit.ts/.lit.js)`),{framework:`lit`,confidence:`high`,evidence:r,warnings:i};if(e.includes(`.qwik.`))return r.push(`Explicit Qwik naming convention (.qwik.tsx/.qwik.jsx)`),{framework:`qwik`,confidence:`high`,evidence:r,warnings:i};let a=new Map;for(let[e,t]of this.frameworkRegistry){let i=this.calculateFrameworkScore(n,t,r);a.set(e,i)}let o=Array.from(a.entries()).sort(([,e],[,t])=>t-e),[s,c]=o[0]||[`unknown`,0],[l,u]=o[1]||[`unknown`,0],d;return c>=3&&c-u>=2?d=`high`:c>=2?d=`medium`:(d=`low`,i.push(`Framework detection has low confidence - consider adding explicit JSX import source or use naming convention (.solid.tsx, .preact.tsx)`)),c===u&&c>0&&(i.push(`Ambiguous detection between ${s} and ${l} - consider using naming convention`),d=`low`),{framework:c>0?s:`unknown`,confidence:d,evidence:r,warnings:i}}extractDetectionCriteria(e,t){return{fileExtension:this.getFileExtension(e),jsxImportSource:this.parseJSXImportSource(t),imports:this.extractImportStatements(t),content:t}}calculateFrameworkScore(e,t,n){let r=0;e.jsxImportSource&&t.jsxImportSources.includes(e.jsxImportSource)&&(r+=3,n.push(`JSX import source: @jsxImportSource ${e.jsxImportSource}`));for(let i of t.detectionPatterns.imports)e.imports.some(e=>i.test(e))&&(r+=2,n.push(`Framework import detected: ${i.source}`));for(let i of t.detectionPatterns.content)i.test(e.content)&&(r+=1,n.push(`Framework-specific content pattern: ${i.source}`));return t.fileExtensions.includes(e.fileExtension)&&(r+=.5,n.push(`File extension: ${e.fileExtension}`)),r}parseJSXImportSource(e){let t=/@jsxImportSource\s+([^\s*]+)/.exec(e);if(t)return t[1]}extractImportStatements(e){let t=[],n=/from\s+['"]([^'"]+)['"]/g,r=/import\s+['"]([^'"]+)['"]/g,i=/require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,a;for(a=n.exec(e);a!==null;a=n.exec(e))t.push(a[1]);for(a=r.exec(e);a!==null;a=r.exec(e))t.push(a[1]);for(a=i.exec(e);a!==null;a=i.exec(e))t.push(a[1]);return t}getFileExtension(e){if(e.includes(`.solid.`))return`.solid.tsx`;if(e.includes(`.preact.`))return`.preact.tsx`;if(e.includes(`.react.`))return`.react.tsx`;if(e.includes(`.lit.`))return`.lit.ts`;let t=e.lastIndexOf(`.`);return t===-1?``:e.substring(t)}getDefaultFrameworkConfigs(){return{preact:{name:`preact`,fileExtensions:[`.tsx`,`.jsx`,`.preact.tsx`,`.preact.jsx`],jsxImportSources:[`preact`],ssrModules:[`preact-render-to-string`],hydrationModules:[`preact`],detectionPatterns:{imports:[/^preact$/,/^preact\//,/preact-render-to-string/],content:[/\buseState\b/,/\buseEffect\b/,/\buseCallback\b/,/\buseMemo\b/,/\buseRef\b/,/from\s+['"]preact['"]/],jsxPragmas:[`@jsxImportSource preact`]}},solid:{name:`solid`,fileExtensions:[`.tsx`,`.jsx`,`.solid.tsx`,`.solid.jsx`],jsxImportSources:[`solid-js`],ssrModules:[`solid-js/web`],hydrationModules:[`solid-js/web`],detectionPatterns:{imports:[/^solid-js$/,/^solid-js\//,/solid-js\/web/],content:[/\bcreateSignal\b/,/\bcreateEffect\b/,/\bcreateMemo\b/,/\bcreateResource\b/,/\bonMount\b/,/\bonCleanup\b/,/from\s+['"]solid-js['"]/],jsxPragmas:[`@jsxImportSource solid-js`]}},vue:{name:`vue`,fileExtensions:[`.vue`],jsxImportSources:[`vue`],ssrModules:[`vue/server-renderer`],hydrationModules:[`vue`],detectionPatterns:{imports:[/^vue$/,/^@vue\//,/vue\/server-renderer/],content:[/<template>/,/<script>/,/<style>/,/\bref\b/,/\breactive\b/,/\bcomputed\b/,/\bwatchEffect\b/,/from\s+['"]vue['"]/],jsxPragmas:[`@jsxImportSource vue`]}},svelte:{name:`svelte`,fileExtensions:[`.svelte`],jsxImportSources:[`svelte`],ssrModules:[`svelte/server`],hydrationModules:[`svelte`],detectionPatterns:{imports:[/^svelte$/,/^svelte\//,/svelte\/store/],content:[/<script>/,/<style>/,/\$:/,/\bonMount\b/,/\bafterUpdate\b/,/\bbeforeUpdate\b/,/from\s+['"]svelte['"]/],jsxPragmas:[`@jsxImportSource svelte`]}},react:{name:`react`,fileExtensions:[`.jsx`,`.tsx`,`.react.jsx`,`.react.tsx`],jsxImportSources:[`react`],ssrModules:[`react-dom/server`],hydrationModules:[`react-dom/client`],detectionPatterns:{imports:[/^react$/,/^react\//,/^react-dom$/,/^react-dom\//,/from\s+['"]react['"]/,/from\s+['"]react\/[^'"]+['"]/,/from\s+['"]react-dom['"]/],content:[/\buseState\b/,/\buseEffect\b/,/\buseContext\b/,/\buseReducer\b/,/\buseCallback\b/,/\buseMemo\b/,/\buseRef\b/,/\buseTransition\b/,/\buseDeferredValue\b/,/\buseId\b/,/\buseImperativeHandle\b/,/\buseLayoutEffect\b/,/["']use client["']/,/["']use server["']/,/from\s+['"]react['"]/,/import\s+.*\s+from\s+['"]react['"]/],jsxPragmas:[`@jsxImportSource react`]}},lit:{name:`lit`,fileExtensions:[`.ts`,`.js`,`.lit.ts`,`.lit.js`],jsxImportSources:[`lit`],ssrModules:[`@lit-labs/ssr`],hydrationModules:[`lit`],detectionPatterns:{imports:[/^lit$/,/^lit\//,/^@lit\//,/^@lit-labs\/ssr/,/from\s+['"]lit['"]/,/from\s+['"]lit\/[^'"]+['"]/,/from\s+['"]@lit\/[^'"]+['"]/],content:[/\bLitElement\b/,/\bcustomElement\b/,/@customElement/,/@property/,/@state/,/@query/,/@queryAll/,/\bhtml`/,/\bcss`/,/extends\s+LitElement/,/from\s+['"]lit['"]/,/import\s+.*\s+from\s+['"]lit['"]/],jsxPragmas:[`@jsxImportSource lit`]}},qwik:{name:`qwik`,fileExtensions:[`.tsx`,`.jsx`,`.qwik.tsx`,`.qwik.jsx`],jsxImportSources:[`@builder.io/qwik`],ssrModules:[`@builder.io/qwik/server`],hydrationModules:[`@builder.io/qwik`],detectionPatterns:{imports:[/^@builder\.io\/qwik$/,/^@builder\.io\/qwik\//,/from\s+['"]@builder\.io\/qwik['"]/,/from\s+['"]@builder\.io\/qwik\/[^'"]+['"]/],content:[/\bcomponent\$/,/\buseSignal\b/,/\buseStore\b/,/\buseTask\$/,/\buseVisibleTask\$/,/\buseResource\$/,/\buseContext\b/,/\buseContextProvider\b/,/\$\(\s*\(/,/from\s+['"]@builder\.io\/qwik['"]/,/import\s+.*\s+from\s+['"]@builder\.io\/qwik['"]/],jsxPragmas:[`@jsxImportSource @builder.io/qwik`]}}}}addFrameworkConfig(e,t){this.frameworkRegistry.set(e,t)}getFrameworkConfigs(){return new Map(this.frameworkRegistry)}validateFrameworkConfig(e){let t=[];return(!e.name||e.name.trim()===``)&&t.push(`Framework name is required`),(!e.fileExtensions||e.fileExtensions.length===0)&&t.push(`At least one file extension is required`),(!e.detectionPatterns.imports||e.detectionPatterns.imports.length===0)&&t.push(`At least one import pattern is required for detection`),(!e.ssrModules||e.ssrModules.length===0)&&t.push(`At least one SSR module is required`),(!e.hydrationModules||e.hydrationModules.length===0)&&t.push(`At least one hydration module is required`),t}}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module provides a centralized registry for framework configurations,
|
|
5
5
|
* validation utilities, and management of framework-specific detection patterns.
|
|
6
6
|
*/
|
|
7
|
-
import type { FrameworkConfig } from
|
|
7
|
+
import type { FrameworkConfig } from "./enhanced-framework-detector.ts";
|
|
8
8
|
export interface FrameworkRegistryConfig {
|
|
9
9
|
enableValidation: boolean;
|
|
10
10
|
allowCustomFrameworks: boolean;
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Integration system exports
|
|
3
3
|
* Central export point for all integration-related functionality
|
|
4
4
|
*/
|
|
5
|
+
export { clearIntegrationCache, detectAndLoadIntegration, detectFrameworkFromContent, detectFrameworkFromPath, getLoadedIntegrations, isIntegrationLoaded, loadIntegration, preloadIntegrations, } from "./loader.ts";
|
|
5
6
|
export { IntegrationRegistry, registry } from "./registry.ts";
|
|
6
|
-
export { loadIntegration, detectAndLoadIntegration, detectFrameworkFromPath, detectFrameworkFromContent, preloadIntegrations, getLoadedIntegrations, clearIntegrationCache, isIntegrationLoaded, } from "./loader.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{
|
|
1
|
+
export{clearIntegrationCache,detectAndLoadIntegration,detectFrameworkFromContent,detectFrameworkFromPath,getLoadedIntegrations,isIntegrationLoaded,loadIntegration,preloadIntegrations}from"./loader.js";export{IntegrationRegistry,registry}from"./registry.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{statSync as e}from"node:fs";import{dirname as t,join as n}from"node:path";function r(){let r=process.cwd();for(let i=0;i<10;i++){try{if(e(n(r,`packages`,`integrations`)).isDirectory())return r}catch{}let i=t(r);if(i===r)break;r=i}return process.cwd()}export class IntegrationRegistry{integrations=new Map;loadingPromises=new Map;register(e){if(!e.name)throw Error(`Integration must have a name`);this.integrations.set(e.name,e)}get(e){return this.integrations.get(e)}has(e){return this.integrations.has(e)}async load(e){let t=this.integrations.get(e);if(t)return t;let n=this.loadingPromises.get(e);if(n)return n;let r=this.loadIntegration(e);this.loadingPromises.set(e,r);try{let e=await r;return this.register(e),e}finally{this.loadingPromises.delete(e)}}async loadIntegration(e){let t=`${e}Integration`;try{let n=await import(`@useavalon/${e}`),r=n[t]||n.default;if(r)return r}catch{}try{let i=await import(`file://${n(r(),`packages`,`integrations`,e,`mod.ts`)}`),a=i[t]||i.default;if(a)return a}catch{}throw Error(`Failed to load integration for framework '${e}'. Make sure @useavalon/${e} is installed.\nInstall it with: bun add @useavalon/${e}`)}getAll(){return Array.from(this.integrations.values())}getAllNames(){return Array.from(this.integrations.keys())}unregister(e){return this.integrations.delete(e)}clear(){this.integrations.clear(),this.loadingPromises.clear()}get size(){return this.integrations.size}}globalThis.__avalonIntegrationRegistry??=new IntegrationRegistry;export const registry=globalThis.__avalonIntegrationRegistry;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import type { LayoutContext, LayoutDiscoveryOptions,
|
|
1
|
+
import { LayoutCacheManager } from "./layout-cache-manager.ts";
|
|
2
|
+
import { LayoutComposer } from "./layout-composer.ts";
|
|
3
|
+
import { LayoutDataLoader } from "./layout-data-loader.ts";
|
|
4
|
+
import { LayoutDiscovery } from "./layout-discovery.ts";
|
|
5
|
+
import { LayoutMatcher } from "./layout-matcher.ts";
|
|
6
|
+
import type { LayoutContext, LayoutDiscoveryOptions, PageModule, ResolvedLayout } from "./layout-types.ts";
|
|
7
7
|
interface IEnhancedLayoutResolver {
|
|
8
8
|
resolveAndRender(routePath: string, pageModule: PageModule, context: LayoutContext): Promise<ResolvedLayout>;
|
|
9
9
|
getCachedResolution(routePath: string): ResolvedLayout | null;
|
|
@@ -53,8 +53,8 @@ export declare class EnhancedLayoutResolver implements IEnhancedLayoutResolver {
|
|
|
53
53
|
totalResolutions: number;
|
|
54
54
|
averageResolutionTime: number;
|
|
55
55
|
errorCount: number;
|
|
56
|
-
cacheStats: ReturnType<LayoutCacheManager[
|
|
57
|
-
discoveryStats: ReturnType<LayoutDiscovery[
|
|
56
|
+
cacheStats: ReturnType<LayoutCacheManager["getStats"]>;
|
|
57
|
+
discoveryStats: ReturnType<LayoutDiscovery["getCacheStats"]>;
|
|
58
58
|
};
|
|
59
59
|
updateOptions(options: Partial<EnhancedLayoutResolverOptions>): void;
|
|
60
60
|
getOptions(): Required<EnhancedLayoutResolverOptions>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{render as e}from"preact-render-to-string";import{
|
|
1
|
+
import{render as e}from"preact-render-to-string";import{defaultCacheConfig as t,LayoutCacheManager as n}from"./layout-cache-manager.js";import{LayoutComposer as r}from"./layout-composer.js";import{LayoutDataLoader as i}from"./layout-data-loader.js";import{LayoutDiscovery as a}from"./layout-discovery.js";import{LayoutMatcher as o}from"./layout-matcher.js";function s(e,t){return e(t)}export class EnhancedLayoutResolver{layoutDiscovery;layoutMatcher;layoutComposer;layoutDataLoader;cache;cacheManager;options;constructor(e){this.options={baseDirectory:e.baseDirectory,filePattern:e.filePattern||`_layout.tsx`,excludeDirectories:e.excludeDirectories||[`node_modules`,`.git`,`dist`],enableWatching:e.enableWatching||!1,developmentMode:e.developmentMode||!1,enableCaching:e.enableCaching??!0,cacheTTL:e.cacheTTL||300*1e3,maxCacheSize:e.maxCacheSize||1e3,enableMetrics:e.enableMetrics??!0,enableDebugInfo:e.enableDebugInfo||!1},this.layoutDiscovery=new a(this.options),this.layoutMatcher=new o({developmentMode:this.options.developmentMode}),this.layoutComposer=new r(this.options),this.layoutDataLoader=new i({developmentMode:this.options.developmentMode,enableParallelLoading:!0,continueOnError:!0}),this.cache={resolved:new Map,handlers:new Map,data:new Map,ttl:new Map},this.cacheManager=new n({...t,defaultTtl:this.options.cacheTTL,maxEntries:this.options.maxCacheSize,enableStats:this.options.enableMetrics})}async resolveLayouts(e,t,n){let r=performance.now(),i=this.generateCacheKey(e,t,n);if(this.options.enableCaching){let t=this.cacheManager.getResolvedLayout(i);if(t)return this.options.developmentMode&&console.log(`[EnhancedLayoutResolver] Cache hit for route: ${e}`),{...t,metadata:{...t.metadata,cacheHit:!0}}}let a=[],o=[];try{o=await this.layoutComposer.resolveLayouts(e,t);let r=await this.layoutDataLoader.loadLayoutData(o,n),{errors:i}=this.layoutDataLoader.processLoadingResults(r,o);a.push(...i)}catch(t){a.push({layoutPath:e,errorType:`rendering`,timestamp:Date.now()}),this.options.developmentMode&&console.warn(`[EnhancedLayoutResolver] Error resolving layouts:`,t)}let s=performance.now()-r,c={handlers:o,dataLoaders:o.map(e=>e.loader).filter(e=>e!==void 0),errorBoundaries:[],streamingComponents:[],metadata:{totalLayouts:o.length,resolutionTime:s,cacheHit:!1}};if(this.options.enableCaching){this.cacheManager.setResolvedLayout(i,c);for(let e of o)this.cacheManager.addDependency(i,e.path)}return this.options.developmentMode&&(a.length>0&&console.warn(`[EnhancedLayoutResolver] ${a.length} error(s) during layout resolution for ${e}`),console.log(`[EnhancedLayoutResolver] Resolved ${o.length} layouts for ${e} in ${s.toFixed(2)}ms`)),c}async resolveAndRender(e,t,n){let r=await this.resolveLayouts(e,t,n);this.options.developmentMode&&console.log(`[EnhancedLayoutResolver] Rendering ${r.handlers.length} layouts for ${e}`);let i=await this.layoutDataLoader.loadLayoutData(r.handlers,n),{data:a}=this.layoutDataLoader.processLoadingResults(i,r.handlers);return this.options.developmentMode&&this.renderLayoutsToString(r,t,n,a),r}renderLayoutsToString(t,n,r,i=[]){try{let a=n.default??(()=>null);for(let e=t.handlers.length-1;e>=0;e--){let r=t.handlers[e].component,o=a,c=i[e]||{};a=e=>s(r,{...e,data:c,frontmatter:n.frontmatter,children:s(o,e)})}return e(s(a,{children:null,data:{},route:{path:new URL(r.request.url).pathname,params:r.params,query:r.query}}))}catch(e){return this.options.developmentMode&&console.warn(`[EnhancedLayoutResolver] Rendering failed:`,e),``}}getCachedResolution(e){return this.cacheManager.getResolvedLayout(e)}invalidateCacheByFilePath(e){return this.cacheManager.invalidateByFilePath(e)}clearCache(){this.cacheManager.clear(),this.cache.resolved.clear(),this.cache.handlers.clear(),this.cache.data.clear(),this.cache.ttl.clear(),this.layoutDiscovery.clearCache(),this.layoutComposer.clearCache()}setCaching(e){this.options.enableCaching=e,e||this.clearCache()}generateCacheKey(e,t,n){return`${e}:${t.layoutConfig?JSON.stringify(t.layoutConfig):``}:${n.request.method}:${n.request.url}`}getResolverStats(){let e=this.cacheManager.getStats(),t=this.layoutDiscovery.getCacheStats();return{cacheSize:e.totalEntries,cacheHitRate:this.cacheManager.getHitRate(),totalResolutions:e.hits+e.misses,averageResolutionTime:0,errorCount:0,cacheStats:e,discoveryStats:t}}updateOptions(e){Object.assign(this.options,e),e.developmentMode!==void 0&&this.layoutDataLoader.updateOptions({developmentMode:e.developmentMode})}getOptions(){return{...this.options}}getLayoutDiscovery(){return this.layoutDiscovery}getLayoutMatcher(){return this.layoutMatcher}getLayoutComposer(){return this.layoutComposer}getLayoutDataLoader(){return this.layoutDataLoader}getCacheManager(){return this.cacheManager}destroy(){this.cacheManager.destroy()}}export function createEnhancedLayoutResolver(e){return new EnhancedLayoutResolver(e)}export const EnhancedLayoutResolverUtils={createBasicConfig(e,t=!1){return{baseDirectory:e,developmentMode:t,enableCaching:!0,enableMetrics:t,enableDebugInfo:t}},createProductionConfig(e){return{baseDirectory:e,developmentMode:!1,enableCaching:!0,enableMetrics:!1,enableDebugInfo:!1}}};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { LayoutDiscovery } from
|
|
2
|
-
import type {
|
|
1
|
+
import { LayoutDiscovery } from "./layout-discovery.ts";
|
|
2
|
+
import type { LayoutConfig, LayoutDiscoveryOptions, LayoutHandler, PageModule } from "./layout-types.ts";
|
|
3
3
|
/**
|
|
4
4
|
* Layout composition control system that handles page-level layout customization.
|
|
5
5
|
* Provides support for skipLayouts, replaceLayout, onlyLayouts, and customLayout configurations.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{statSync as e}from"node:fs";import{relative as t,resolve as n}from"node:path";import r from"node:process";import{LayoutDiscovery as i}from"./layout-discovery.js";function a(e){return/^[A-Za-z]:[\\/]/.test(e)?`file:///${e.replaceAll(`\\`,`/`)}`:e}function o(t){try{return e(t),!0}catch{return!1}}function s(e){return new RegExp(e.replaceAll(`*`,`.*`))}export class LayoutComposer{layoutDiscovery;customLayoutCache=new Map;developmentMode;constructor(e){this.layoutDiscovery=new i(e),this.developmentMode=e.developmentMode||!1}async resolveLayouts(e,t){try{let n=t.layoutConfig;if(!n)return await this.layoutDiscovery.buildLayoutChain(new URL(`http://localhost${e}`));if(n.replaceLayout)return this.developmentMode&&console.log(`[LayoutComposer] Replacing all layouts for route: ${e}`),await this.handleReplaceLayout(e,n);let r=await this.layoutDiscovery.buildLayoutChain(new URL(`http://localhost${e}`));return await this.applyConfiguration(r,n)}catch(t){return this.developmentMode&&console.warn(`[LayoutComposer] Error resolving layouts for ${e}: ${t instanceof Error?t.message:String(t)}`),await this.layoutDiscovery.buildLayoutChain(new URL(`http://localhost${e}`))}}async applyConfiguration(e,t){let n=[...e];return t.onlyLayouts&&t.onlyLayouts.length>0&&(n=await this.applyOnlyLayouts(n,t.onlyLayouts)),t.skipLayouts&&t.skipLayouts.length>0&&(n=this.applySkipLayouts(n,t.skipLayouts)),t.customLayout&&(n=await this.addCustomLayout(n,t.customLayout)),n}async handleReplaceLayout(e,t){if(t.customLayout){let e=await this.loadCustomLayout(t.customLayout);return e?[e]:[]}return[]}matchesLayoutPattern(e,n){if(n.includes(`*`)){let i=s(n);return i.test(e.path)||i.test(t(r.cwd(),e.path))}return e.path===n||e.path.endsWith(n)||t(r.cwd(),e.path)===n||t(r.cwd(),e.path).endsWith(n)}applySkipLayouts(e,n){return e.filter(e=>{let i=n.some(t=>this.matchesLayoutPattern(e,t));return i&&this.developmentMode&&console.log(`[LayoutComposer] Skipping layout: ${t(r.cwd(),e.path)}`),!i})}async applyOnlyLayouts(e,n){let i=[];for(let a of n){let n=e.filter(e=>this.matchesLayoutPattern(e,a));if(n.length>0)i.push(...n),this.developmentMode&&console.log(`[LayoutComposer] Kept layouts from onlyLayouts: ${n.map(e=>t(r.cwd(),e.path)).join(`, `)}`);else{let e=await this.loadCustomLayout(a);e&&(i.push(e),this.developmentMode&&console.log(`[LayoutComposer] Added custom layout from onlyLayouts: ${a}`))}}return i.sort((e,t)=>e.priority-t.priority),i}async addCustomLayout(e,n){try{let i=await this.loadCustomLayout(n);if(!i)return this.developmentMode&&console.warn(`[LayoutComposer] Failed to load custom layout: ${n}`),e;let a={...i,priority:Math.max(...e.map(e=>e.priority),0)+10},o=[...e,a];return o.sort((e,t)=>e.priority-t.priority),this.developmentMode&&console.log(`[LayoutComposer] Added custom layout: ${t(r.cwd(),n)}`),o}catch(t){return this.developmentMode&&console.warn(`[LayoutComposer] Error adding custom layout ${n}: ${t instanceof Error?t.message:String(t)}`),e}}resolveLayoutPath(e){if(e.startsWith(`/`)||e.startsWith(`file://`)||/^[A-Za-z]:[\\/]/.test(e))return e;let t=this.layoutDiscovery.getOptions().baseDirectory;return[n(e),n(`src`,e),n(`src/pages`,e),n(`src/layouts`,e),n(t,`..`,e),n(t,e)].find(e=>o(e))||e}async loadCustomLayout(e){if(this.customLayoutCache.has(e))return this.customLayoutCache.get(e);try{let t=this.resolveLayoutPath(e);if(!o(t))return this.developmentMode&&console.warn(`[LayoutComposer] Custom layout file not found: ${t}`),null;let n=await import(a(t));if(!n.default||typeof n.default!=`function`)return this.developmentMode&&console.warn(`[LayoutComposer] Custom layout file does not export a default component: ${t}`),null;let r={component:n.default,loader:n.layoutLoader,path:t,priority:1e3};return this.customLayoutCache.set(e,r),r}catch(t){return this.developmentMode&&console.warn(`[LayoutComposer] Failed to load custom layout ${e}: ${t instanceof Error?t.message:String(t)}`),null}}validateLayoutConfig(e){let t=[];return e.replaceLayout&&e.onlyLayouts&&e.onlyLayouts.length>0&&t.push(`replaceLayout and onlyLayouts cannot be used together`),e.replaceLayout&&e.skipLayouts&&e.skipLayouts.length>0&&t.push(`replaceLayout and skipLayouts cannot be used together`),e.skipLayouts&&!Array.isArray(e.skipLayouts)&&t.push(`skipLayouts must be an array of strings`),e.onlyLayouts&&!Array.isArray(e.onlyLayouts)&&t.push(`onlyLayouts must be an array of strings`),e.customLayout&&typeof e.customLayout!=`string`&&t.push(`customLayout must be a string path`),{valid:t.length===0,errors:t}}getCompositionStats(){return{customLayoutCacheSize:this.customLayoutCache.size,discoveryStats:this.layoutDiscovery.getCacheStats()}}clearCache(){this.customLayoutCache.clear(),this.layoutDiscovery.clearCache()}clearCustomLayoutCache(){this.customLayoutCache.clear()}getLayoutDiscovery(){return this.layoutDiscovery}setDevelopmentMode(e){this.developmentMode=e}isDevelopmentMode(){return this.developmentMode}}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LayoutContext, LayoutData,
|
|
1
|
+
import type { LayoutContext, LayoutData, LayoutErrorInfo, LayoutHandler } from "./layout-types.ts";
|
|
2
2
|
/**
|
|
3
3
|
* Layout data loading error with context information
|
|
4
4
|
*/
|
|
@@ -111,7 +111,7 @@ export declare class LayoutDataLoader {
|
|
|
111
111
|
* Preload data for layouts that are likely to be needed soon
|
|
112
112
|
* Requirements: 2.1, 2.2
|
|
113
113
|
*/
|
|
114
|
-
preloadLayoutData(layoutHandlers: LayoutHandler[], context: LayoutContext, priority?:
|
|
114
|
+
preloadLayoutData(layoutHandlers: LayoutHandler[], context: LayoutContext, priority?: "high" | "medium" | "low"): Promise<void>;
|
|
115
115
|
/**
|
|
116
116
|
* Gets current loading options
|
|
117
117
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export type { LayoutDiscoveryOptions } from
|
|
1
|
+
import type { LayoutContext, LayoutData, LayoutDiscoveryOptions, LayoutErrorInfo, LayoutHandler, LayoutRoute } from "./layout-types.ts";
|
|
2
|
+
export type { LayoutDiscoveryOptions } from "./layout-types.ts";
|
|
3
3
|
/**
|
|
4
4
|
* Simplified Layout Discovery System
|
|
5
5
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{statSync as e}from"node:fs";import{join as t,relative as n,resolve as r}from"node:path";function i(e){return/^[A-Za-z]:[\\/]/.test(e)?`file:///${e.replaceAll(`\\`,`/`)}`:e}function a(t){try{return e(t),!0}catch{return!1}}function o(e){let t=e.split(`/`).filter(Boolean),n=[``];for(let e=0;e<t.length;e++)n.push(`/`+t.slice(0,e+1).join(`/`));return n}export class LayoutDiscovery{layoutCache=new Map;routeCache=new Map;baseDirectory;filePattern;developmentMode;constructor(e){this.baseDirectory=r(e.baseDirectory),this.filePattern=e.filePattern||`_layout.tsx`,this.developmentMode=e.developmentMode||!1,this.developmentMode&&console.log(`[LayoutDiscovery] baseDirectory=${this.baseDirectory}, filePattern=${this.filePattern}`)}discoverLayouts(e){let n=`layouts-${e}`;if(this.routeCache.has(n))return Promise.resolve(this.routeCache.get(n));let r=[],i=o(e);for(let e of i){let n=t(e===``?this.baseDirectory:t(this.baseDirectory,e),this.filePattern);if(a(n)){let t=e===``?0:e.split(`/`).filter(Boolean).length;r.push({pattern:new URLPattern({pathname:t===0?`*`:`${e}/*`}),layoutPath:n,priority:t*10,type:t===0?`root`:`nested`,depth:t})}}return r.sort((e,t)=>e.priority-t.priority),this.routeCache.set(n,r),Promise.resolve(r)}async buildLayoutChain(e){let t=await this.discoverLayouts(e.pathname),n=[];for(let e of t)try{let t=await this.loadLayout(e.layoutPath);t&&n.push(t)}catch(t){this.developmentMode&&console.warn(`[Layout] Failed to load ${e.layoutPath}: ${t instanceof Error?t.message:String(t)}`)}return n}async buildLayoutChainWithData(e,t){let n=await this.buildLayoutChain(e),r=[],i=[];for(let e of n)if(e.loader)try{let n=await e.loader(t);r.push(n)}catch(t){this.developmentMode&&console.warn(`[Layout] Data loader error for ${e.path}:`,t),i.push({layoutPath:e.path,errorType:`loader`,timestamp:Date.now()}),r.push({})}else r.push({});return{handlers:n,data:r,errors:i}}async loadLayout(e){if(this.layoutCache.has(e))return this.layoutCache.get(e);try{let t=await import(i(e));if(!t.default||typeof t.default!=`function`)return this.developmentMode&&console.warn(`[Layout] No default export in ${e}`),null;let r=n(this.baseDirectory,e).split(`/`).filter(Boolean),a=Math.max(0,(r.length-1)*10),o={component:t.default,loader:t.layoutLoader,path:e,priority:a};return this.layoutCache.set(e,o),o}catch(t){return this.developmentMode&&console.warn(`[Layout] Failed to load ${e}: ${t instanceof Error?t.message:String(t)}`),null}}clearCache(){this.layoutCache.clear(),this.routeCache.clear()}clearLayoutCache(e){this.layoutCache.delete(e),this.routeCache.clear()}getCacheStats(){return{layoutCount:this.layoutCache.size,routeCacheCount:this.routeCache.size}}getOptions(){return{baseDirectory:this.baseDirectory,filePattern:this.filePattern,developmentMode:this.developmentMode}}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export class BuiltInLayoutRules{static API_ROUTES_SKIP_LAYOUTS={matches:e=>e.path.startsWith(`/api/`),apply:!1,priority:100};static MOBILE_LAYOUT_DETECTION={matches:(e,t)=>{let n=e.headers.get(`user-agent`)?.toLowerCase()||``,r=/mobile|android|iphone|ipad|phone|tablet/i.test(n);return t?.includes(`/mobile/`)??!1?!r:r},apply:!1,priority:50};static HEADER_BASED_SKIP={matches:e=>{let t=e.headers.get(`x-skip-layout`);return t===`true`||t===`1`},apply:!1,priority:90};static ADMIN_LAYOUT_RESTRICTION={matches:(e,t)=>t?.includes(`/admin/`)?!e.path.startsWith(`/admin/`):!1,apply:!1,priority:60};static getAllRules(){return[
|
|
1
|
+
export class BuiltInLayoutRules{static API_ROUTES_SKIP_LAYOUTS={matches:e=>e.path.startsWith(`/api/`),apply:!1,priority:100};static MOBILE_LAYOUT_DETECTION={matches:(e,t)=>{let n=e.headers.get(`user-agent`)?.toLowerCase()||``,r=/mobile|android|iphone|ipad|phone|tablet/i.test(n);return t?.includes(`/mobile/`)??!1?!r:r},apply:!1,priority:50};static HEADER_BASED_SKIP={matches:e=>{let t=e.headers.get(`x-skip-layout`);return t===`true`||t===`1`},apply:!1,priority:90};static ADMIN_LAYOUT_RESTRICTION={matches:(e,t)=>t?.includes(`/admin/`)?!e.path.startsWith(`/admin/`):!1,apply:!1,priority:60};static getAllRules(){return[BuiltInLayoutRules.API_ROUTES_SKIP_LAYOUTS,BuiltInLayoutRules.MOBILE_LAYOUT_DETECTION,BuiltInLayoutRules.HEADER_BASED_SKIP,BuiltInLayoutRules.ADMIN_LAYOUT_RESTRICTION]}}export class LayoutMatcher{rules=[];developmentMode;constructor(e={}){this.developmentMode=e.developmentMode||!1,this.addBuiltInRules()}addRule(e){if(!e.matches||typeof e.matches!=`function`)throw Error(`Layout rule must have a valid matches function`);if(typeof e.apply!=`boolean`)throw TypeError(`Layout rule must have a boolean apply property`);if(typeof e.priority!=`number`)throw TypeError(`Layout rule must have a numeric priority`);this.rules.push(e),this.sortRulesByPriority(),this.developmentMode&&console.log(`[LayoutMatcher] Added rule with priority ${e.priority}`)}removeRule(e){let t=this.rules.indexOf(e);t>-1&&(this.rules.splice(t,1),this.developmentMode&&console.log(`[LayoutMatcher] Removed rule with priority ${e.priority}`))}shouldApplyLayout(e,t){try{let n=this.getMatchingRules(t,e);if(n.length===0)return!0;let r=this.resolveRuleConflicts(n);return this.developmentMode&&console.log(`[LayoutMatcher] Layout ${e} for route ${t.path}: ${r?`APPLY`:`SKIP`} (${n.length} rules matched)`),r}catch(t){return this.developmentMode&&console.warn(`[LayoutMatcher] Error evaluating rules for layout ${e}: ${t instanceof Error?t.message:String(t)}`),!0}}getRules(){return[...this.rules]}clearRules(){this.rules=[],this.developmentMode&&console.log(`[LayoutMatcher] Cleared all rules`)}addBuiltInRules(){for(let t of BuiltInLayoutRules.getAllRules())this.rules.push(t);this.sortRulesByPriority(),this.developmentMode&&console.log(`[LayoutMatcher] Added ${this.rules.length} built-in rules`)}sortRulesByPriority(){this.rules.sort((e,t)=>t.priority-e.priority)}getMatchingRules(e,t){let n=[];for(let r of this.rules)try{r.matches(e,t)&&n.push(r)}catch(e){this.developmentMode&&console.warn(`[LayoutMatcher] Error in rule evaluation: ${e instanceof Error?e.message:String(e)}`)}return n}resolveRuleConflicts(e){if(e.length===0)return!0;if(e.length===1)return e[0].apply;let t=new Map;for(let n of e)t.has(n.priority)||t.set(n.priority,[]),t.get(n.priority).push(n);let n=Array.from(t.keys()).sort((e,t)=>t-e),r=t.get(n[0]);return r.length===1?r[0].apply:this.resolveEqualPriorityConflicts(r)}resolveEqualPriorityConflicts(e){let t=e.filter(e=>e.apply).length,n=e.filter(e=>!e.apply).length;return n>t?(this.developmentMode&&console.log(`[LayoutMatcher] Conflict resolution: SKIP`),!1):t>n?(this.developmentMode&&console.log(`[LayoutMatcher] Conflict resolution: APPLY`),!0):(this.developmentMode&&console.log(`[LayoutMatcher] Conflict resolution: SKIP (tie-breaker)`),!1)}static createCustomRule(e,t,n=10){return{matches:e,apply:t,priority:n}}static createPathRule(e,t,n=10){return{matches:typeof e==`string`?t=>t.path.includes(e):t=>e.test(t.path),apply:t,priority:n}}static createHeaderRule(e,t,n,r=10){return{matches:n=>{let r=n.headers.get(e.toLowerCase());return r?typeof t==`string`?r===t:t.test(r):!1},apply:n,priority:r}}static createMethodRule(e,t,n=10){let r=new Set((Array.isArray(e)?e:[e]).map(e=>e.toUpperCase()));return{matches:e=>r.has(e.method.toUpperCase()),apply:t,priority:n}}getDebugInfo(e,t){let n=this.getMatchingRules(t,e),r=this.shouldApplyLayout(e,t);return{totalRules:this.rules.length,matchingRules:n.map(e=>({priority:e.priority,apply:e.apply})),finalDecision:r,conflictResolution:n.length>1?`priority-based`:`single-rule`}}}
|
|
@@ -16,7 +16,7 @@ export interface LayoutContext {
|
|
|
16
16
|
export type LayoutData = Record<string, unknown>;
|
|
17
17
|
export type LayoutLoader = (ctx: LayoutContext) => Promise<LayoutData>;
|
|
18
18
|
export interface LayoutProps {
|
|
19
|
-
children: import(
|
|
19
|
+
children: import("preact").ComponentChildren;
|
|
20
20
|
data: LayoutData;
|
|
21
21
|
frontmatter?: Record<string, unknown>;
|
|
22
22
|
route: {
|
|
@@ -35,7 +35,7 @@ export interface LayoutRoute {
|
|
|
35
35
|
pattern: URLPattern;
|
|
36
36
|
layoutPath: string;
|
|
37
37
|
priority: number;
|
|
38
|
-
type:
|
|
38
|
+
type: "root" | "nested";
|
|
39
39
|
depth: number;
|
|
40
40
|
}
|
|
41
41
|
export interface LayoutDiscoveryOptions {
|
|
@@ -64,7 +64,7 @@ export interface LayoutRule {
|
|
|
64
64
|
}
|
|
65
65
|
export interface LayoutErrorInfo {
|
|
66
66
|
layoutPath: string;
|
|
67
|
-
errorType:
|
|
67
|
+
errorType: "component" | "loader" | "rendering" | "island";
|
|
68
68
|
timestamp: number;
|
|
69
69
|
componentStack?: string;
|
|
70
70
|
errorBoundary?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { JSX } from
|
|
2
|
-
import { type
|
|
3
|
-
import type { IslandProps } from
|
|
1
|
+
import type { JSX } from "preact";
|
|
2
|
+
import { type AnalysisReport, type AnalyzerOptions } from "../core/components/component-analyzer.ts";
|
|
3
|
+
import type { IslandProps } from "./types.ts";
|
|
4
4
|
/**
|
|
5
5
|
* Analyze component file for rendering strategy
|
|
6
6
|
*
|
|
@@ -31,7 +31,7 @@ export declare function analyzeComponentFile(src: string, options?: AnalyzerOpti
|
|
|
31
31
|
*/
|
|
32
32
|
export declare function renderComponentSSROnly({ src, condition, props, framework: explicitFramework, renderOptions, }: {
|
|
33
33
|
src: string;
|
|
34
|
-
condition: IslandProps[
|
|
34
|
+
condition: IslandProps["condition"];
|
|
35
35
|
props: Record<string, unknown>;
|
|
36
36
|
framework?: string;
|
|
37
37
|
renderOptions: AnalyzerOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{readFile as e}from"node:fs/promises";import{analyzeComponentContent as t}from"../core/components/component-analyzer.js";import{resolveIslandPath as n}from"./framework-detection.js";import{getCachedAnalysis as r,getCachedPath as i,setCachedAnalysis as a,setCachedPath as o}from"./render-cache.js";function s(e,t){let n=e.split(`/`).pop()?.replace(/\.(tsx|jsx|vue|svelte|ts|js)$/,``)||``,r=e.split(`.`).pop()||`tsx`;return[t.startsWith(`/`)?t.substring(1):t,e.startsWith(`/`)?e.substring(1):e,`src/islands/${n}.${r}`,`src/islands/${n}.tsx`,`islands/${n}.${r}`,`islands/${n}.tsx`,`src/islands/${n}.svelte`,`src/islands/${n}.vue`,`src/islands/${n}.solid.tsx`]}async function c(t){try{return await e(t,`utf-8`)}catch{return null}}export async function analyzeComponentFile(e,l={}){let u=r(e);if(u)return u;let d=i(e);d||=await n(e);let f=s(e,d);for(let n of f){let r=await c(n);if(r!==null){o(e,n);let i=t(n,r,l);return a(e,i),i}}throw Error(`Component file not found: ${e}`)}export async function renderComponentSSROnly({src:e,condition:t,props:n,framework:r,renderOptions:i}){try{let{default:a}=await import(`./island.js`),{loadIntegration:o}=await import(`./integration-loader.js`),{detectFramework:s}=await import(`./framework-detection.js`),c;c=r||(e.endsWith(`.vue`)?`vue`:e.endsWith(`.svelte`)?`svelte`:e.endsWith(`.tsx`)||e.endsWith(`.jsx`)||e.endsWith(`.ts`)||e.endsWith(`.js`)?await s(e):`preact`);let l=await o(c),u=globalThis.__viteDevServer,d=process.env.NODE_ENV!==`production`;return a({src:e,condition:t,props:n,children:(await l.render({component:null,props:n,src:e,condition:t,ssrOnly:!0,viteServer:u,isDev:d})).html,ssr:!0,framework:c,ssrOnly:!0,renderOptions:i,hydrationData:void 0})}catch(t){throw process.env.NODE_ENV!==`production`&&console.error(`SSR-only rendering failed for ${e}:`,t),t}}
|
|
@@ -14,4 +14,4 @@ typeof globalThis<`u`&&!globalThis.__svelteSSRCSS&&(globalThis.__svelteSSRCSS=ne
|
|
|
14
14
|
`).replace(/\n\n+/g,`
|
|
15
15
|
|
|
16
16
|
`).trim()}export function applyCSSScoping(e,t){return e.replace(/([^{}]+){/g,(e,n)=>{let r=n.trim();return r.startsWith(`@`)||r.includes(`[data-${t}]`)?e:r.includes(`:global(`)?`${r.replace(/:global\(([^)]+)\)/g,`$1`)} {`:`${r.split(`,`).map(e=>applySelectorScoping(e.trim(),t)).join(`, `)} {`})}export function applySelectorScoping(e,t){if(!e||e.length===0||e.includes(`[data-${t}]`))return e;let n=e.split(/(\s*[>+~]\s*|\s+)/);if(n.length>1){let e=n[0].trim(),r=n.slice(1).join(``);return d(e,t)+r}return d(e,t)}function d(e,t){let n=e.match(/^([^:]+)(::.*)?$/);if(n){let[,e,r]=n;return`${e}[data-${t}]${r||``}`}let r=e.match(/^([^:]+)(:.*)?$/);if(r){let[,e,n]=r;return`${e}[data-${t}]${n||``}`}return`${e}[data-${t}]`}export function optimizeComponentCSS(e){try{let t=p(f(e)).join(`
|
|
17
|
-
`);return process.env.NODE_ENV===`production`?minifyCSS(t):t}catch(t){return console.warn(`⚠️ Failed to optimize component CSS:`,t),e}}function f(e){let t=[],n=``,r=0,i=!1,a=``;for(let o=0;o<e.length;o++){let s=e[o],c=o>0?e[o-1]:``;if((s===`"`||s===`'`)&&c!==`\\`&&(i?s===a&&(i=!1,a=``):(i=!0,a=s)),!i){if(s===`{`)r++;else if(s===`}`&&(r--,r===0)){n+=s;let e=n.trim();e&&!h(e)&&t.push(e),n=``;continue}}n+=s}return n.trim()&&t.push(n.trim()),t}function p(e){let t=new Map,n=[];for(let r=0;r<e.length;r++){let i=e[r],a=m(i);if(a){let e=t.get(a);if(e)n[e.index]=i,t.set(a,{rule:i,index:e.index});else{let e=n.length;n.push(i),t.set(a,{rule:i,index:e})}}else n.push(i)}return n.filter(e=>e!==null)}function m(e){let t=e.match(/^([^{]+)\{([^}]+)\}/);if(!t)return null;let n=t[1].trim();return t[2].trim(),n}function h(e){let t=e.match(/^[^{]+\{([^}]*)\}/);if(!t)return!0;let n=t[1].trim();return n.length===0||n===`;`}export function minifyCSS(e){return e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/\s+/g,` `).replace(/\s*{\s*/g,`{`).replace(/\s*}\s*/g,`}`).replace(/\s*;\s*/g,`;`).replace(/;\s*}/g,`}`).replace(/;}/g,`}`).trim()}export function generateComponentScopeId(e,t=`component`){return`${t}-${e.replace(/^\/+/,``).replace(/\.(svelte|tsx|jsx|vue|ts|js)$/,``).replace(/[^a-zA-Z0-9
|
|
17
|
+
`);return process.env.NODE_ENV===`production`?minifyCSS(t):t}catch(t){return console.warn(`⚠️ Failed to optimize component CSS:`,t),e}}function f(e){let t=[],n=``,r=0,i=!1,a=``;for(let o=0;o<e.length;o++){let s=e[o],c=o>0?e[o-1]:``;if((s===`"`||s===`'`)&&c!==`\\`&&(i?s===a&&(i=!1,a=``):(i=!0,a=s)),!i){if(s===`{`)r++;else if(s===`}`&&(r--,r===0)){n+=s;let e=n.trim();e&&!h(e)&&t.push(e),n=``;continue}}n+=s}return n.trim()&&t.push(n.trim()),t}function p(e){let t=new Map,n=[];for(let r=0;r<e.length;r++){let i=e[r],a=m(i);if(a){let e=t.get(a);if(e)n[e.index]=i,t.set(a,{rule:i,index:e.index});else{let e=n.length;n.push(i),t.set(a,{rule:i,index:e})}}else n.push(i)}return n.filter(e=>e!==null)}function m(e){let t=e.match(/^([^{]+)\{([^}]+)\}/);if(!t)return null;let n=t[1].trim();return t[2].trim(),n}function h(e){let t=e.match(/^[^{]+\{([^}]*)\}/);if(!t)return!0;let n=t[1].trim();return n.length===0||n===`;`}export function minifyCSS(e){return e.replace(/\/\*[\s\S]*?\*\//g,``).replace(/\s+/g,` `).replace(/\s*{\s*/g,`{`).replace(/\s*}\s*/g,`}`).replace(/\s*;\s*/g,`;`).replace(/;\s*}/g,`}`).replace(/;}/g,`}`).trim()}export function generateComponentScopeId(e,t=`component`){return`${t}-${e.replace(/^\/+/,``).replace(/\.(svelte|tsx|jsx|vue|ts|js)$/,``).replace(/[^a-zA-Z0-9/]/g,`-`).replace(/\/+/g,`-`).replace(/-+/g,`-`).replace(/^-|-$/g,``).toLowerCase()}-${simpleHash(e)}`}export function simpleHash(e){let t=0;for(let n=0;n<e.length;n++){let r=e.charCodeAt(n);t=(t<<5)-t+r,t&=t}return Math.abs(t).toString(36).substring(0,6)}
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
* Exports all types and functions for discovering island components
|
|
5
5
|
* in nested directory structures.
|
|
6
6
|
*/
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
9
|
-
export {
|
|
10
|
-
export {
|
|
11
|
-
export type {
|
|
12
|
-
export {
|
|
13
|
-
export type {
|
|
14
|
-
export {
|
|
7
|
+
export { createIslandRegistry, IslandRegistry, } from "./registry.ts";
|
|
8
|
+
export type { ImportPathOptions, ResolutionResult, } from "./resolver.ts";
|
|
9
|
+
export { createIslandResolver, IslandResolver, } from "./resolver.ts";
|
|
10
|
+
export { discoverAllIslands, discoverIslandDirectories, discoverIslandsInDirectory, getDefaultIslandsPath, getQualifiedIslandName, hasDefaultIslandsDirectory, isIslandsDirectory, parseQualifiedIslandName, } from "./scanner.ts";
|
|
11
|
+
export type { DiscoveredIsland, IslandChangeEvent, IslandCollision, IslandDirectory, IslandDiscoveryConfig, IslandFileExtension, } from "./types.ts";
|
|
12
|
+
export { DEFAULT_DISCOVERY_CONFIG, ISLAND_FILE_EXTENSIONS, isSupportedIslandExtension, } from "./types.ts";
|
|
13
|
+
export type { CircularDependency, ValidationError, ValidationResult, ValidationWarning, } from "./validator.ts";
|
|
14
|
+
export { createIslandValidator, formatCircularDependency, formatValidationError, formatValidationResult, formatValidationWarning, IslandValidator, validateAllIslands, } from "./validator.ts";
|
|
15
15
|
export type { IslandChangeCallback, IslandWatcherOptions, } from "./watcher.ts";
|
|
16
|
-
export {
|
|
16
|
+
export { createIslandWatcher, IslandWatcher, } from "./watcher.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export{
|
|
1
|
+
export{createIslandRegistry,IslandRegistry}from"./registry.js";export{createIslandResolver,IslandResolver}from"./resolver.js";export{discoverAllIslands,discoverIslandDirectories,discoverIslandsInDirectory,getDefaultIslandsPath,getQualifiedIslandName,hasDefaultIslandsDirectory,isIslandsDirectory,parseQualifiedIslandName}from"./scanner.js";export{DEFAULT_DISCOVERY_CONFIG,ISLAND_FILE_EXTENSIONS,isSupportedIslandExtension}from"./types.js";export{createIslandValidator,formatCircularDependency,formatValidationError,formatValidationResult,formatValidationWarning,IslandValidator,validateAllIslands}from"./validator.js";export{createIslandWatcher,IslandWatcher}from"./watcher.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Central registry for all discovered islands with resolution capabilities.
|
|
5
5
|
* Handles registration, resolution by name/namespace, and collision detection.
|
|
6
6
|
*/
|
|
7
|
-
import type { DiscoveredIsland,
|
|
7
|
+
import type { DiscoveredIsland, IslandCollision, IslandDirectory, IslandDiscoveryConfig } from "./types.ts";
|
|
8
8
|
/**
|
|
9
9
|
* Central registry for all discovered islands.
|
|
10
10
|
* Provides registration, resolution, and collision detection capabilities.
|
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
* - The resolver returns `ambiguous: true` with alternatives
|
|
39
39
|
* - Default directory always has priority for simple name resolution
|
|
40
40
|
*/
|
|
41
|
-
import type { DiscoveredIsland } from "./types.ts";
|
|
42
41
|
import type { IslandRegistry } from "./registry.ts";
|
|
42
|
+
import type { DiscoveredIsland } from "./types.ts";
|
|
43
43
|
/**
|
|
44
44
|
* Result of resolving an island reference
|
|
45
45
|
*/
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{relative as e}from"node:path";import{
|
|
2
|
-
`)}`),Error(n)}return t}findSimilarNames(e){let
|
|
1
|
+
import{relative as e}from"node:path";import{getQualifiedIslandName as t,parseQualifiedIslandName as n}from"./scanner.js";const r={isDevelopment:!0,basePath:`/`,projectRoot:``,absolute:!1};export class IslandResolver{_registry;_projectRoot;constructor(e,t){this._registry=e,this._projectRoot=t}get registry(){return this._registry}get projectRoot(){return this._projectRoot}resolve(e){let t=this.normalizeReference(e),n=this.resolveExplicitPath(t);if(n)return n;if(t.includes(`/`)){let e=this.resolveQualifiedName(t);if(e)return e}return this.resolveByName(t)}normalizeReference(e){let t=e.trim().replace(/^\/+|\/+$/g,``);t=t.replace(/\\/g,`/`);for(let e of[/\.solid\.(tsx|jsx)$/,/\.react\.(tsx|jsx)$/,/\.lit\.(ts|js)$/,/\.preact\.(tsx|jsx)$/,/\.(tsx|ts|jsx|js|vue|svelte)$/])if(e.test(t)){t=t.replace(e,``);break}return t}resolveExplicitPath(e){if(!e.includes(`islands/`))return null;let t=this._registry.getAllIslands();for(let n of t){let t=n.relativePath.replace(/\.[^.]+$/,``),r=[/\.solid$/,/\.react$/,/\.lit$/,/\.preact$/],i=t;for(let e of r)i=i.replace(e,``);if(i===e||i.endsWith(`/`+e)||t===e||t.endsWith(`/`+e))return{island:n,importPath:this.generateImportPath(n),ambiguous:!1}}return null}resolveQualifiedName(e){let{namespace:t,name:r}=n(e),i=this._registry.resolve(r,t);if(!i)return null;let a=this._registry.findByName(r),o=a.length>1;return{island:i,importPath:this.generateImportPath(i),ambiguous:o,alternatives:o?a.filter(e=>e!==i):void 0}}resolveByName(e){let t=this._registry.findByName(e);if(t.length===0)return null;let n=[...t].sort((e,t)=>e.directory.isDefault&&!t.directory.isDefault?-1:!e.directory.isDefault&&t.directory.isDefault?1:e.namespace.localeCompare(t.namespace)),r=n[0],i=t.length>1;return{island:r,importPath:this.generateImportPath(r),ambiguous:i,alternatives:i?n.slice(1):void 0}}generateImportPath(t,n={}){let i={...r,...n},a=i.projectRoot||this._projectRoot;if(i.absolute)return t.filePath;if(i.isDevelopment){let n=e(a,t.filePath).replace(/\\/g,`/`);return`${i.basePath}${n}`}return`${i.basePath}${t.relativePath}`}generateQualifiedImportPath(e){return t(e)}getResolutionOrder(){return[`Island Resolution Order:`,`1. Explicit path-based references (e.g., 'src/modules/auth/islands/Counter')`,`2. Qualified name matches (e.g., 'modules/auth/Counter')`,`3. Default /src/islands/ directory (highest priority for unqualified names)`,`4. Nested directories in alphabetical order by namespace`,``,`Discovered directories (in priority order):`,...this._registry.directories.map((e,t)=>` ${t+1}. ${e.relativePath}${e.isDefault?` (default)`:``}`)]}isAmbiguous(e){return this.resolve(e)?.ambiguous??!1}getAllMatches(e){let t=this.normalizeReference(e);if(t.includes(`/`)&&!t.includes(`islands/`)){let{namespace:e,name:r}=n(t),i=this._registry.resolve(r,e);return i?[i]:[]}return this._registry.findByName(t)}suggestQualifiedNames(e){return this._registry.findByName(e).map(e=>t(e))}resolveOrThrow(e){let t=this.resolve(e);if(!t){let t=this.findSimilarNames(e),n=`Island not found: "${e}"`;throw t.length>0&&(n+=`\n\nDid you mean one of these?\n${t.map(e=>` - ${e}`).join(`
|
|
2
|
+
`)}`),Error(n)}return t}findSimilarNames(e){let n=this._registry.getAllIslands(),r=e.toLowerCase();return n.filter(e=>{let n=e.name.toLowerCase(),i=t(e).toLowerCase();return n.includes(r)||r.includes(n)||i.includes(r)||this.levenshteinDistance(n,r)<=3}).map(e=>t(e)).slice(0,5)}levenshteinDistance(e,t){let n=[];for(let e=0;e<=t.length;e++)n[e]=[e];for(let t=0;t<=e.length;t++)n[0][t]=t;for(let r=1;r<=t.length;r++)for(let i=1;i<=e.length;i++)t.charAt(r-1)===e.charAt(i-1)?n[r][i]=n[r-1][i-1]:n[r][i]=Math.min(n[r-1][i-1]+1,n[r][i-1]+1,n[r-1][i]+1);return n[t.length][e.length]}}export function createIslandResolver(e,t){return new IslandResolver(e,t)}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Recursively scans the source directory to discover all islands directories.
|
|
5
5
|
* Supports nested patterns like /src/modules/[module]/islands/.
|
|
6
6
|
*/
|
|
7
|
-
import type { IslandDirectory, IslandDiscoveryConfig
|
|
7
|
+
import type { DiscoveredIsland, IslandDirectory, IslandDiscoveryConfig } from "./types.ts";
|
|
8
8
|
/**
|
|
9
9
|
* Discover all island directories within the source directory.
|
|
10
10
|
* Uses recursive scanning to find all directories named "islands".
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{stat as e,readdir as t}from"node:fs/promises";import{basename as n,dirname as r,extname as i,relative as a,resolve as o}from"node:path";import{DEFAULT_DISCOVERY_CONFIG as s,isSupportedIslandExtension as c}from"./types.js";export async function discoverIslandDirectories(t,n={}){let r={...s,...n},i=o(t,r.rootDir),a=[];try{if(!(await e(i)).isDirectory())return a}catch{return a}return await u(i,t,r,a),a.sort((e,t)=>e.isDefault&&!t.isDefault?-1:!e.isDefault&&t.isDefault?1:e.relativePath.localeCompare(t.relativePath)),a}async function u(e,n,r,i){try{let s=await t(e,{withFileTypes:!0});for(let t of s){if(!t.isDirectory())continue;let s=o(e,t.name);if(!d(a(n,s),r.exclude)){if(t.name===`islands`){let e=f(s,n,r);i.push(e);continue}await u(s,n,r,i)}}}catch(t){(!(t instanceof Error)||t.code!==`EACCES`)&&console.warn(`Warning: Could not scan directory ${e}:`,t)}}function d(e,t){let n=e.replace(/\\/g,`/`);for(let e of t)if(n===e||n.startsWith(e+`/`)||n.includes(`/`+e+`/`)||n.endsWith(`/`+e))return!0;return!1}function f(e,t,n){let i=a(o(t,n.rootDir),e),s=i===`islands`,c=``;return s||(c=r(i).replace(/\\/g,`/`),n.namespaces[c]&&(c=n.namespaces[c])),{path:e,relativePath:i.replace(/\\/g,`/`),namespace:c,isDefault:s}}export function isIslandsDirectory(e){return n(e)===`islands`}export function getDefaultIslandsPath(e,t=`src`){return o(e,t,`islands`)}export async function hasDefaultIslandsDirectory(t,n=`src`){let r=getDefaultIslandsPath(t,n);try{return(await e(r)).isDirectory()}catch{return!1}}export async function discoverIslandsInDirectory(e,n){let r=[];try{let a=await t(e.path,{withFileTypes:!0});for(let t of a){if(!t.isFile()||!c(i(t.name)))continue;let a=p(t.name,e,n);r.push(a)}}catch(t){console.warn(`Warning: Could not scan islands directory ${e.path}:`,t)}return r.sort((e,t)=>e.name.localeCompare(t.name)),r}export async function discoverAllIslands(e,t={}){let n=await discoverIslandDirectories(e,t),r=[];for(let t of n){let n=await discoverIslandsInDirectory(t,e);r.push(...n)}return r}function p(e,t,n){let r=i(e),s=m(e),c=o(t.path,e),l=a(n,c).replace(/\\/g,`/`),u=h(e);return{name:s,filePath:c,relativePath:l,namespace:t.namespace,framework:u,extension:r,directory:t}}function m(e){let t=e;for(let e of[`.solid.tsx`,`.solid.jsx`,`.react.tsx`,`.react.jsx`,`.lit.ts`,`.lit.js`,`.preact.tsx`,`.preact.jsx`])if(t.endsWith(e))return t.slice(0,-e.length);for(let e of[`.tsx`,`.ts`,`.jsx`,`.js`,`.vue`,`.svelte`])if(t.endsWith(e))return t.slice(0,-e.length);return t}function h(e){let t=e.toLowerCase();if(t.includes(`.solid.`))return`solid`;if(t.includes(`.react.`))return`react`;if(t.includes(`.lit.`))return`lit`;if(t.includes(`.preact.`))return`preact`;if(t.includes(`.qwik.`))return`qwik`;if(e.endsWith(`.vue`))return`vue`;if(e.endsWith(`.svelte`))return`svelte`;if((e.endsWith(`.ts`)||e.endsWith(`.js`))&&!e.endsWith(`.d.ts`)){let t=m(e);if(/^[A-Z]/.test(t))return`lit`}return e.endsWith(`.tsx`)||e.endsWith(`.jsx`)?`preact`:`unknown`}export function getQualifiedIslandName(e){return e.namespace===``?e.name:`${e.namespace}/${e.name}`}export function parseQualifiedIslandName(e){let t=e.lastIndexOf(`/`);return t===-1?{namespace:``,name:e}:{namespace:e.slice(0,t),name:e.slice(t+1)}}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Validates island components and directory structure.
|
|
5
5
|
* Provides validation for exports, naming conventions, and circular dependencies.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { DiscoveredIsland, IslandDirectory } from "./types.ts";
|
|
8
8
|
/**
|
|
9
9
|
* Result of validating an island or directory
|
|
10
10
|
*/
|