dalila 1.9.2 → 1.9.4
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/README.md +35 -23
- package/dist/cli/check.d.ts +3 -0
- package/dist/cli/check.js +902 -0
- package/dist/cli/index.js +53 -11
- package/dist/cli/routes-generator.d.ts +25 -0
- package/dist/cli/routes-generator.js +28 -7
- package/dist/router/route-tables.d.ts +28 -7
- package/dist/router/route-tables.js +19 -0
- package/dist/router/router.js +87 -3
- package/dist/routes.generated.d.ts +2 -0
- package/dist/routes.generated.js +76 -0
- package/dist/routes.generated.manifest.d.ts +4 -0
- package/dist/routes.generated.manifest.js +32 -0
- package/dist/routes.generated.types.d.ts +11 -0
- package/dist/routes.generated.types.js +37 -0
- package/dist/runtime/bind.d.ts +47 -2
- package/dist/runtime/bind.js +702 -26
- package/dist/runtime/component.d.ts +74 -0
- package/dist/runtime/component.js +40 -0
- package/dist/runtime/fromHtml.d.ts +3 -2
- package/dist/runtime/fromHtml.js +0 -15
- package/dist/runtime/index.d.ts +4 -2
- package/dist/runtime/index.js +2 -1
- package/package.json +2 -2
- package/scripts/dev-server.cjs +47 -7
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dalila Component System
|
|
3
|
+
*
|
|
4
|
+
* Declarative component definitions for use with bind().
|
|
5
|
+
* This module contains only types, defineComponent, and pure helpers —
|
|
6
|
+
* no imports from bind.ts (avoids circular dependency).
|
|
7
|
+
*
|
|
8
|
+
* @module dalila/runtime/component
|
|
9
|
+
*/
|
|
10
|
+
import type { Signal } from '../core/signal.js';
|
|
11
|
+
export type PropConstructor = StringConstructor | NumberConstructor | BooleanConstructor | ArrayConstructor | ObjectConstructor | FunctionConstructor;
|
|
12
|
+
export interface PropDefinition {
|
|
13
|
+
type: PropConstructor;
|
|
14
|
+
required?: boolean;
|
|
15
|
+
default?: unknown;
|
|
16
|
+
}
|
|
17
|
+
export type PropOption = PropConstructor | PropDefinition;
|
|
18
|
+
export type PropsSchema = Record<string, PropOption>;
|
|
19
|
+
type InferPropType<T extends PropConstructor> = T extends StringConstructor ? string : T extends NumberConstructor ? number : T extends BooleanConstructor ? boolean : T extends ArrayConstructor ? unknown[] : T extends ObjectConstructor ? Record<string, unknown> : T extends FunctionConstructor ? Function : unknown;
|
|
20
|
+
type InferPropOptionType<T extends PropOption> = T extends PropConstructor ? InferPropType<T> : T extends {
|
|
21
|
+
type: infer C extends PropConstructor;
|
|
22
|
+
default: infer D;
|
|
23
|
+
} ? D extends (...args: any[]) => infer R ? R : InferPropType<C> : T extends {
|
|
24
|
+
type: infer C extends PropConstructor;
|
|
25
|
+
} ? InferPropType<C> : unknown;
|
|
26
|
+
export type TypedPropSignals<P extends PropsSchema> = {
|
|
27
|
+
[K in keyof P]: Signal<InferPropOptionType<P[K]>>;
|
|
28
|
+
};
|
|
29
|
+
/** @deprecated Use TypedPropSignals instead */
|
|
30
|
+
export type PropSignals<P> = {
|
|
31
|
+
[K in keyof P]: Signal<unknown>;
|
|
32
|
+
};
|
|
33
|
+
export type EmitsSchema = Record<string, unknown>;
|
|
34
|
+
export type RefsSchema = Record<string, Element>;
|
|
35
|
+
export type TypedEmit<E extends EmitsSchema> = <K extends keyof E & string>(event: K, payload: E[K]) => void;
|
|
36
|
+
export type TypedRef<R extends RefsSchema> = <K extends keyof R & string>(name: K) => R[K] | null;
|
|
37
|
+
export interface TypedSetupContext<E extends EmitsSchema = EmitsSchema, R extends RefsSchema = RefsSchema> {
|
|
38
|
+
ref: TypedRef<R>;
|
|
39
|
+
refs(): Readonly<Partial<R>>;
|
|
40
|
+
emit: TypedEmit<E>;
|
|
41
|
+
onMount(fn: () => void): void;
|
|
42
|
+
onCleanup(fn: () => void): void;
|
|
43
|
+
}
|
|
44
|
+
/** @deprecated Use TypedSetupContext instead */
|
|
45
|
+
export interface SetupContext {
|
|
46
|
+
ref(name: string): Element | null;
|
|
47
|
+
refs(): Readonly<Record<string, Element>>;
|
|
48
|
+
emit(event: string, ...args: unknown[]): void;
|
|
49
|
+
onMount(fn: () => void): void;
|
|
50
|
+
onCleanup(fn: () => void): void;
|
|
51
|
+
}
|
|
52
|
+
export interface ComponentDefinition<P extends PropsSchema = PropsSchema, E extends EmitsSchema = EmitsSchema, R extends RefsSchema = RefsSchema> {
|
|
53
|
+
tag: string;
|
|
54
|
+
template: string;
|
|
55
|
+
props?: P;
|
|
56
|
+
setup?: (props: TypedPropSignals<P>, ctx: TypedSetupContext<E, R>) => Record<string, unknown>;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Erased component handle used by bind() and mount().
|
|
60
|
+
* The generic P from defineComponent is erased here so that
|
|
61
|
+
* any Component can be stored in a Record<string, Component> registry
|
|
62
|
+
* without variance issues.
|
|
63
|
+
*/
|
|
64
|
+
export interface Component {
|
|
65
|
+
readonly __dalila_component: true;
|
|
66
|
+
readonly definition: ComponentDefinition<any, any, any>;
|
|
67
|
+
}
|
|
68
|
+
export declare function defineComponent<P extends PropsSchema = PropsSchema, E extends EmitsSchema = EmitsSchema, R extends RefsSchema = RefsSchema>(def: ComponentDefinition<P, E, R>): Component;
|
|
69
|
+
export declare function isComponent(value: unknown): value is Component;
|
|
70
|
+
export declare function normalizePropDef(option: PropOption): PropDefinition;
|
|
71
|
+
export declare function coercePropValue(raw: string, type: PropConstructor): unknown;
|
|
72
|
+
export declare function kebabToCamel(str: string): string;
|
|
73
|
+
export declare function camelToKebab(str: string): string;
|
|
74
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dalila Component System
|
|
3
|
+
*
|
|
4
|
+
* Declarative component definitions for use with bind().
|
|
5
|
+
* This module contains only types, defineComponent, and pure helpers —
|
|
6
|
+
* no imports from bind.ts (avoids circular dependency).
|
|
7
|
+
*
|
|
8
|
+
* @module dalila/runtime/component
|
|
9
|
+
*/
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// defineComponent
|
|
12
|
+
// ============================================================================
|
|
13
|
+
export function defineComponent(def) {
|
|
14
|
+
if (!def.tag || !def.tag.includes('-')) {
|
|
15
|
+
throw new Error(`[Dalila] defineComponent: tag "${def.tag}" must contain a hyphen.`);
|
|
16
|
+
}
|
|
17
|
+
return { __dalila_component: true, definition: def };
|
|
18
|
+
}
|
|
19
|
+
export function isComponent(value) {
|
|
20
|
+
return typeof value === 'object' && value !== null && value.__dalila_component === true;
|
|
21
|
+
}
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Prop Helpers
|
|
24
|
+
// ============================================================================
|
|
25
|
+
export function normalizePropDef(option) {
|
|
26
|
+
return typeof option === 'function' ? { type: option } : option;
|
|
27
|
+
}
|
|
28
|
+
export function coercePropValue(raw, type) {
|
|
29
|
+
switch (type) {
|
|
30
|
+
case Number: return Number(raw);
|
|
31
|
+
case Boolean: return raw !== 'false' && raw !== '0';
|
|
32
|
+
default: return raw;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function kebabToCamel(str) {
|
|
36
|
+
return str.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
37
|
+
}
|
|
38
|
+
export function camelToKebab(str) {
|
|
39
|
+
return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
|
|
40
|
+
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
* @module dalila/runtime
|
|
10
10
|
*/
|
|
11
11
|
import type { Scope } from '../core/scope.js';
|
|
12
|
-
export interface FromHtmlOptions {
|
|
12
|
+
export interface FromHtmlOptions<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
13
13
|
/** Bind context — keys map to {placeholder} tokens in the HTML */
|
|
14
|
-
data?:
|
|
14
|
+
data?: T;
|
|
15
15
|
/** Child nodes to inject into [data-slot="children"] */
|
|
16
16
|
children?: Node | DocumentFragment | Node[];
|
|
17
17
|
/** Route scope — registers bind cleanup automatically */
|
|
@@ -32,4 +32,5 @@ export interface FromHtmlOptions {
|
|
|
32
32
|
* const el = fromHtml('<div><div data-slot="children"></div></div>', { children });
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
|
+
export declare function fromHtml<T extends Record<string, unknown>>(html: string, options: FromHtmlOptions<T>): HTMLElement;
|
|
35
36
|
export declare function fromHtml(html: string, options?: FromHtmlOptions): HTMLElement;
|
package/dist/runtime/fromHtml.js
CHANGED
|
@@ -9,21 +9,6 @@
|
|
|
9
9
|
* @module dalila/runtime
|
|
10
10
|
*/
|
|
11
11
|
import { bind } from './bind.js';
|
|
12
|
-
/**
|
|
13
|
-
* Parse an HTML string into a bound DOM element.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* // Static HTML
|
|
18
|
-
* const el = fromHtml('<div><h1>Hello</h1></div>');
|
|
19
|
-
*
|
|
20
|
-
* // With data binding
|
|
21
|
-
* const el = fromHtml('<div>{name}</div>', { data: { name: 'Dalila' } });
|
|
22
|
-
*
|
|
23
|
-
* // Layout with children slot
|
|
24
|
-
* const el = fromHtml('<div><div data-slot="children"></div></div>', { children });
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
12
|
export function fromHtml(html, options = {}) {
|
|
28
13
|
const { data, children, scope } = options;
|
|
29
14
|
const template = document.createElement('template');
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module dalila/runtime
|
|
8
8
|
*/
|
|
9
|
-
export { bind, autoBind } from './bind.js';
|
|
10
|
-
export type { BindOptions, BindContext, DisposeFunction } from './bind.js';
|
|
9
|
+
export { bind, autoBind, mount, configure } from './bind.js';
|
|
10
|
+
export type { BindOptions, BindContext, BindData, DisposeFunction, BindHandle } from './bind.js';
|
|
11
11
|
export { fromHtml } from './fromHtml.js';
|
|
12
12
|
export type { FromHtmlOptions } from './fromHtml.js';
|
|
13
|
+
export { defineComponent } from './component.js';
|
|
14
|
+
export type { Component, ComponentDefinition, PropsSchema, PropSignals, SetupContext, TypedPropSignals, TypedSetupContext, EmitsSchema, RefsSchema, TypedEmit, TypedRef, } from './component.js';
|
package/dist/runtime/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dalila",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "DOM-first reactive framework based on signals",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"build": "tsc && node scripts/ensure-cli-executable.cjs",
|
|
101
101
|
"dev": "tsc --watch",
|
|
102
102
|
"serve": "node scripts/dev-server.cjs",
|
|
103
|
-
"test": "npm run build && node --test",
|
|
103
|
+
"test": "npm run build && node --test --test-concurrency=1 test/*.test.js",
|
|
104
104
|
"test:e2e": "npm run build && playwright test",
|
|
105
105
|
"test:watch": "jest --watch",
|
|
106
106
|
"clean": "rm -rf dist",
|
package/scripts/dev-server.cjs
CHANGED
|
@@ -718,6 +718,12 @@ const server = http.createServer((req, res) => {
|
|
|
718
718
|
const effectivePath =
|
|
719
719
|
requestPath === '/' || requestPath === '/index.html' ? defaultEntry : requestPath;
|
|
720
720
|
let resolvedRequestPath = effectivePath;
|
|
721
|
+
const fetchModeHeader = req.headers['sec-fetch-mode'];
|
|
722
|
+
const fetchDestHeader = req.headers['sec-fetch-dest'];
|
|
723
|
+
const fetchMode = Array.isArray(fetchModeHeader) ? fetchModeHeader[0] : fetchModeHeader;
|
|
724
|
+
const fetchDest = Array.isArray(fetchDestHeader) ? fetchDestHeader[0] : fetchDestHeader;
|
|
725
|
+
const isNavigationRequest = fetchMode === 'navigate' || fetchDest === 'document';
|
|
726
|
+
const isScriptRequest = fetchDest === 'script';
|
|
721
727
|
const fsPath = resolvePath(effectivePath);
|
|
722
728
|
|
|
723
729
|
if (!fsPath) {
|
|
@@ -748,17 +754,48 @@ const server = http.createServer((req, res) => {
|
|
|
748
754
|
return;
|
|
749
755
|
}
|
|
750
756
|
} else {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
757
|
+
// Extensionless import — try .ts, then .js
|
|
758
|
+
const tsPath = targetPath + '.ts';
|
|
759
|
+
const jsPath = targetPath + '.js';
|
|
760
|
+
if (!path.extname(targetPath) && isScriptRequest && fs.existsSync(tsPath)) {
|
|
761
|
+
targetPath = tsPath;
|
|
762
|
+
} else if (!path.extname(targetPath) && isScriptRequest && fs.existsSync(jsPath)) {
|
|
763
|
+
targetPath = jsPath;
|
|
755
764
|
} else {
|
|
756
|
-
|
|
757
|
-
|
|
765
|
+
const spaFallback = resolveSpaFallbackPath(requestPath);
|
|
766
|
+
if (spaFallback) {
|
|
767
|
+
targetPath = spaFallback.fsPath;
|
|
768
|
+
resolvedRequestPath = spaFallback.requestPath;
|
|
769
|
+
} else {
|
|
770
|
+
send(res, 404, 'Not Found');
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
758
773
|
}
|
|
759
774
|
}
|
|
760
775
|
}
|
|
761
776
|
|
|
777
|
+
// Raw import — serve file as `export default` JS module.
|
|
778
|
+
// Triggered by ?raw suffix OR .html imported as script/module.
|
|
779
|
+
const isRawQuery = req.url && req.url.includes('?raw');
|
|
780
|
+
const isHtmlModuleImport = targetPath.endsWith('.html')
|
|
781
|
+
&& isScriptRequest
|
|
782
|
+
&& !isNavigationRequest;
|
|
783
|
+
if (isRawQuery || isHtmlModuleImport) {
|
|
784
|
+
fs.readFile(targetPath, 'utf8', (err, source) => {
|
|
785
|
+
if (err) {
|
|
786
|
+
send(res, err.code === 'ENOENT' ? 404 : 500, err.code === 'ENOENT' ? 'Not Found' : 'Error');
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
const escaped = source.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$/g, '\\$');
|
|
790
|
+
res.writeHead(200, {
|
|
791
|
+
'Content-Type': 'text/javascript; charset=utf-8',
|
|
792
|
+
'Cache-Control': 'no-store, no-cache, must-revalidate',
|
|
793
|
+
});
|
|
794
|
+
res.end(`export default \`${escaped}\`;`);
|
|
795
|
+
});
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
|
|
762
799
|
// TypeScript transpilation (only if ts available)
|
|
763
800
|
if (targetPath.endsWith('.ts') && ts) {
|
|
764
801
|
fs.readFile(targetPath, 'utf8', (err, source) => {
|
|
@@ -1009,5 +1046,8 @@ setupWatcher();
|
|
|
1009
1046
|
startKeepalive();
|
|
1010
1047
|
|
|
1011
1048
|
server.listen(port, () => {
|
|
1012
|
-
console.log(
|
|
1049
|
+
console.log('');
|
|
1050
|
+
console.log(' 🐰 ✂️ Dalila dev server');
|
|
1051
|
+
console.log(` http://localhost:${port}`);
|
|
1052
|
+
console.log('');
|
|
1013
1053
|
});
|