@primate/angular 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/private/Default.d.ts +20 -0
- package/lib/private/Default.js +59 -0
- package/lib/private/INITIAL_PROPS.d.ts +11 -0
- package/lib/private/INITIAL_PROPS.js +3 -0
- package/lib/private/Runtime.d.ts +13 -0
- package/lib/private/Runtime.js +38 -0
- package/lib/private/client/Validated.d.ts +11 -0
- package/lib/private/client/Validated.js +2 -0
- package/lib/private/client/index.d.ts +14 -0
- package/lib/private/client/index.js +72 -0
- package/lib/private/client/validate.d.ts +25 -0
- package/lib/private/client/validate.js +29 -0
- package/lib/private/create-root.d.ts +3 -0
- package/lib/private/create-root.js +105 -0
- package/lib/private/root-selector.d.ts +3 -0
- package/lib/private/root-selector.js +2 -0
- package/lib/public/INITIAL_PROPS.d.ts +2 -0
- package/lib/public/INITIAL_PROPS.js +2 -0
- package/lib/public/Validated.d.ts +2 -0
- package/lib/public/Validated.js +2 -0
- package/lib/public/browser.d.ts +2 -0
- package/lib/public/browser.js +2 -0
- package/lib/public/default.d.ts +4 -0
- package/lib/public/default.js +3 -0
- package/lib/public/runtime.d.ts +4 -0
- package/lib/public/runtime.js +3 -0
- package/lib/public/validate.d.ts +2 -0
- package/lib/public/validate.js +2 -0
- package/package.json +36 -38
- package/src/private/build/client.js +0 -11
- package/src/private/build/compile.js +0 -12
- package/src/private/build/index.js +0 -31
- package/src/private/build/publish.js +0 -27
- package/src/private/build/server.js +0 -11
- package/src/private/client/create-root-client.js +0 -24
- package/src/private/client/create-root.js +0 -24
- package/src/private/client/expose.js +0 -9
- package/src/private/client/index.js +0 -11
- package/src/private/client/root-selector.js +0 -1
- package/src/private/extension.js +0 -1
- package/src/private/name.js +0 -1
- package/src/private/normalize.js +0 -4
- package/src/private/pkgname.js +0 -1
- package/src/private/serve/index.js +0 -29
- package/src/private/serve/render.js +0 -33
- package/src/private/serve/set-mode.js +0 -7
- package/src/public/default.js +0 -10
- package/src/public/runtime.js +0 -8
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import Runtime from "#Runtime";
|
|
2
|
+
import type NextServe from "@primate/core/NextServe";
|
|
3
|
+
import type ServeApp from "@primate/core/ServeApp";
|
|
4
|
+
export default class Default extends Runtime {
|
|
5
|
+
root: {
|
|
6
|
+
create: (depth: number, i18n_active: boolean) => string;
|
|
7
|
+
};
|
|
8
|
+
css: {
|
|
9
|
+
filter: RegExp;
|
|
10
|
+
};
|
|
11
|
+
compile: {
|
|
12
|
+
client: (text: string) => {
|
|
13
|
+
js: string;
|
|
14
|
+
css: string;
|
|
15
|
+
};
|
|
16
|
+
server: (text: string) => string;
|
|
17
|
+
};
|
|
18
|
+
serve(app: ServeApp, next: NextServe): Promise<ServeApp>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=Default.d.ts.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import create_root from "#create-root";
|
|
2
|
+
import Runtime from "#Runtime";
|
|
3
|
+
import { enableProdMode } from "@angular/core";
|
|
4
|
+
import * as ts from "typescript";
|
|
5
|
+
export default class Default extends Runtime {
|
|
6
|
+
root = {
|
|
7
|
+
create: create_root,
|
|
8
|
+
};
|
|
9
|
+
css = {
|
|
10
|
+
filter: /\.component\.(css)$/,
|
|
11
|
+
};
|
|
12
|
+
compile = {
|
|
13
|
+
client: (text) => {
|
|
14
|
+
const result = ts.transpileModule(text, {
|
|
15
|
+
compilerOptions: {
|
|
16
|
+
module: ts.ModuleKind.ESNext,
|
|
17
|
+
target: ts.ScriptTarget.ES2020,
|
|
18
|
+
experimentalDecorators: true,
|
|
19
|
+
emitDecoratorMetadata: true,
|
|
20
|
+
lib: ["es2020", "dom"],
|
|
21
|
+
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const styleMatch = text.match(/styles:\s*\[([\s\S]*?)\]/);
|
|
25
|
+
let css = "";
|
|
26
|
+
if (styleMatch) {
|
|
27
|
+
// Extract and process inline styles
|
|
28
|
+
css = styleMatch[1]
|
|
29
|
+
.replace(/['"`]/g, "")
|
|
30
|
+
.replace(/\\n/g, "\n")
|
|
31
|
+
.trim();
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
js: result.outputText,
|
|
35
|
+
css,
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
server: (text) => {
|
|
39
|
+
// TypeScript compilation for server (SSR)
|
|
40
|
+
const result = ts.transpileModule(text, {
|
|
41
|
+
compilerOptions: {
|
|
42
|
+
module: ts.ModuleKind.ESNext,
|
|
43
|
+
target: ts.ScriptTarget.ES2020,
|
|
44
|
+
experimentalDecorators: true,
|
|
45
|
+
emitDecoratorMetadata: true,
|
|
46
|
+
lib: ["es2020"],
|
|
47
|
+
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
// hinder treeshaking
|
|
51
|
+
return `import "@angular/compiler";\n${result.outputText}`;
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
async serve(app, next) {
|
|
55
|
+
app.mode === "production" && enableProdMode();
|
|
56
|
+
return super.serve(app, next);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=Default.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InjectionToken } from "@angular/core";
|
|
2
|
+
import type Dict from "@rcompat/type/Dict";
|
|
3
|
+
type RootProps = {
|
|
4
|
+
components: any[];
|
|
5
|
+
props: Dict[];
|
|
6
|
+
request: any;
|
|
7
|
+
update?: () => void;
|
|
8
|
+
};
|
|
9
|
+
declare const _default: InjectionToken<RootProps>;
|
|
10
|
+
export default _default;
|
|
11
|
+
//# sourceMappingURL=INITIAL_PROPS.d.ts.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "@angular/compiler";
|
|
2
|
+
import { type Type } from "@angular/core";
|
|
3
|
+
import FrontendModule from "@primate/core/frontend/Module";
|
|
4
|
+
import type Render from "@primate/core/frontend/Render";
|
|
5
|
+
import "zone.js/node";
|
|
6
|
+
export default class Runtime extends FrontendModule<Type<any>> {
|
|
7
|
+
name: string;
|
|
8
|
+
defaultExtensions: string[];
|
|
9
|
+
layouts: boolean;
|
|
10
|
+
client: boolean;
|
|
11
|
+
render: Render<Type<any>>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=Runtime.d.ts.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import INITIAL_PROPS from "#INITIAL_PROPS";
|
|
2
|
+
import root from "#root-selector";
|
|
3
|
+
import "@angular/compiler";
|
|
4
|
+
import { importProvidersFrom, provideZoneChangeDetection, } from "@angular/core";
|
|
5
|
+
import { bootstrapApplication, BrowserModule, provideClientHydration, } from "@angular/platform-browser";
|
|
6
|
+
import { provideServerRendering, renderApplication, } from "@angular/platform-server";
|
|
7
|
+
import FrontendModule from "@primate/core/frontend/Module";
|
|
8
|
+
import "zone.js/node";
|
|
9
|
+
export default class Runtime extends FrontendModule {
|
|
10
|
+
name = "angular";
|
|
11
|
+
defaultExtensions = [".component.ts"];
|
|
12
|
+
layouts = true;
|
|
13
|
+
client = true;
|
|
14
|
+
render = async (RootComponent, props) => {
|
|
15
|
+
const providers = [
|
|
16
|
+
importProvidersFrom(BrowserModule),
|
|
17
|
+
provideServerRendering(),
|
|
18
|
+
provideClientHydration(),
|
|
19
|
+
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
20
|
+
{
|
|
21
|
+
provide: INITIAL_PROPS,
|
|
22
|
+
useValue: props,
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
const bootstrap = (context) => bootstrapApplication(RootComponent, { providers }, context);
|
|
26
|
+
const html = await renderApplication(bootstrap, {
|
|
27
|
+
document: `<${root}></${root}>`,
|
|
28
|
+
});
|
|
29
|
+
const headMatch = html.match(/<head>(.*?)<\/head>/s);
|
|
30
|
+
const bodyRegex = new RegExp(`<${root}>([\\s\\S]*?)<\\/${root}>`);
|
|
31
|
+
const bodyMatch = html.match(bodyRegex);
|
|
32
|
+
return {
|
|
33
|
+
body: bodyMatch?.[1] || html,
|
|
34
|
+
head: headMatch?.[1] || "",
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=Runtime.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Signal } from "@angular/core";
|
|
2
|
+
import type ValidateUpdater from "@primate/core/client/ValidateUpdater";
|
|
3
|
+
import type ValidationError from "@primate/core/client/ValidationError";
|
|
4
|
+
type Validated<T> = {
|
|
5
|
+
error: Signal<null | ValidationError>;
|
|
6
|
+
loading: Signal<boolean>;
|
|
7
|
+
update: (updater: ValidateUpdater<T>) => Promise<void>;
|
|
8
|
+
value: Signal<T>;
|
|
9
|
+
};
|
|
10
|
+
export type { Validated as default };
|
|
11
|
+
//# sourceMappingURL=Validated.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "zone.js";
|
|
2
|
+
import "@angular/compiler";
|
|
3
|
+
import type ClientData from "@primate/core/client/Data";
|
|
4
|
+
import type Dict from "@rcompat/type/Dict";
|
|
5
|
+
type Data = ClientData<{
|
|
6
|
+
components: string[];
|
|
7
|
+
props: Dict[];
|
|
8
|
+
}>;
|
|
9
|
+
export default class AngularClient {
|
|
10
|
+
#private;
|
|
11
|
+
static mount(_component: string, data: ClientData<Data>): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import INITIAL_PROPS from "#INITIAL_PROPS";
|
|
2
|
+
import "zone.js";
|
|
3
|
+
import "@angular/compiler";
|
|
4
|
+
import { NgZone, provideZoneChangeDetection, } from "@angular/core";
|
|
5
|
+
import { bootstrapApplication, provideClientHydration, } from "@angular/platform-browser";
|
|
6
|
+
import spa from "@primate/core/client/spa";
|
|
7
|
+
import * as components from "angular:components";
|
|
8
|
+
import root from "angular:root";
|
|
9
|
+
const make_props = (data) => ({
|
|
10
|
+
components: data.components.map(name => components[name]),
|
|
11
|
+
props: data.props,
|
|
12
|
+
request: {
|
|
13
|
+
...data.request,
|
|
14
|
+
url: new URL(location.href),
|
|
15
|
+
},
|
|
16
|
+
update: () => undefined,
|
|
17
|
+
});
|
|
18
|
+
export default class AngularClient {
|
|
19
|
+
static #app;
|
|
20
|
+
static #root;
|
|
21
|
+
static #zone;
|
|
22
|
+
static async mount(_component, data) {
|
|
23
|
+
const providers = [];
|
|
24
|
+
// Add hydration provider for SSR
|
|
25
|
+
if (data.ssr) {
|
|
26
|
+
providers.push(provideClientHydration());
|
|
27
|
+
}
|
|
28
|
+
// Add zone.js change detection
|
|
29
|
+
providers.push(provideZoneChangeDetection({ eventCoalescing: true }));
|
|
30
|
+
// Create the root component props
|
|
31
|
+
const props = make_props(data);
|
|
32
|
+
// Bootstrap the application
|
|
33
|
+
try {
|
|
34
|
+
this.#app = await bootstrapApplication(root, {
|
|
35
|
+
providers: [
|
|
36
|
+
...providers,
|
|
37
|
+
{
|
|
38
|
+
provide: INITIAL_PROPS,
|
|
39
|
+
useValue: props,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
this.#root = this.#app.components[0];
|
|
44
|
+
// initial props
|
|
45
|
+
if (this.#root.instance) {
|
|
46
|
+
this.#root.instance.p = props;
|
|
47
|
+
// change detection
|
|
48
|
+
this.#app.tick();
|
|
49
|
+
}
|
|
50
|
+
if (data.spa) {
|
|
51
|
+
this.#spa();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.error("Failed to bootstrap Angular application:", error);
|
|
56
|
+
}
|
|
57
|
+
this.#zone = this.#root.injector.get(NgZone);
|
|
58
|
+
}
|
|
59
|
+
static #spa() {
|
|
60
|
+
window.addEventListener("DOMContentLoaded", () => {
|
|
61
|
+
spa((next, update) => {
|
|
62
|
+
const props = { ...make_props(next), update };
|
|
63
|
+
this.#zone.run(() => {
|
|
64
|
+
this.#root.instance.p = props;
|
|
65
|
+
this.#app.tick();
|
|
66
|
+
});
|
|
67
|
+
update?.();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type Validated from "#client/Validated";
|
|
2
|
+
declare const _default: <T>(initial: T) => {
|
|
3
|
+
delete: (url: string, options?: {
|
|
4
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
5
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
6
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
7
|
+
} | undefined) => Validated<T>;
|
|
8
|
+
patch: (url: string, options?: {
|
|
9
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
10
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
11
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
12
|
+
} | undefined) => Validated<T>;
|
|
13
|
+
post: (url: string, options?: {
|
|
14
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
15
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
16
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
17
|
+
} | undefined) => Validated<T>;
|
|
18
|
+
put: (url: string, options?: {
|
|
19
|
+
headers?: import("@rcompat/type/Dict").default<string>;
|
|
20
|
+
map?: ((v: T) => import("@rcompat/type/JSONValue").default) | undefined;
|
|
21
|
+
path?: import("@rcompat/type/JSONPointer").default;
|
|
22
|
+
} | undefined) => Validated<T>;
|
|
23
|
+
};
|
|
24
|
+
export default _default;
|
|
25
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { signal } from "@angular/core";
|
|
2
|
+
import toValidated from "@primate/core/client/toValidated";
|
|
3
|
+
import validate from "@primate/core/client/validate";
|
|
4
|
+
function useValidate(init) {
|
|
5
|
+
const value = signal(init.initial);
|
|
6
|
+
const loading = signal(false);
|
|
7
|
+
const error = signal(null);
|
|
8
|
+
async function update(updater) {
|
|
9
|
+
const previous = value();
|
|
10
|
+
const next = updater(previous);
|
|
11
|
+
value.set(next);
|
|
12
|
+
loading.set(true);
|
|
13
|
+
error.set(null);
|
|
14
|
+
try {
|
|
15
|
+
await validate(init, next);
|
|
16
|
+
}
|
|
17
|
+
catch (e) {
|
|
18
|
+
// rollback
|
|
19
|
+
value.set(previous);
|
|
20
|
+
error.set(e);
|
|
21
|
+
}
|
|
22
|
+
finally {
|
|
23
|
+
loading.set(false);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return { error, loading, update, value };
|
|
27
|
+
}
|
|
28
|
+
export default toValidated(useValidate);
|
|
29
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import root_selector from "#root-selector";
|
|
2
|
+
export default (depth, i18n_active) => {
|
|
3
|
+
const n = depth - 1;
|
|
4
|
+
const layer = (i, child) => {
|
|
5
|
+
const slot = `slot_${i}`;
|
|
6
|
+
const childTemplate = child
|
|
7
|
+
? `<ng-template #${slot}>${child}</ng-template>`
|
|
8
|
+
: "";
|
|
9
|
+
const inputs = child
|
|
10
|
+
? `(has(${i + 1}) ? slotInputs(${i}, ${slot}) : inputs(${i}))`
|
|
11
|
+
: `inputs(${i})`;
|
|
12
|
+
return `${childTemplate}
|
|
13
|
+
<ng-container *ngComponentOutlet="comp(${i}); inputs: ${inputs}">
|
|
14
|
+
</ng-container>
|
|
15
|
+
`;
|
|
16
|
+
};
|
|
17
|
+
let body = layer(n, null);
|
|
18
|
+
for (let i = n - 1; i >= 0; i--)
|
|
19
|
+
body = layer(i, body);
|
|
20
|
+
const i18n_imports = i18n_active
|
|
21
|
+
? `import t from "#i18n";
|
|
22
|
+
import sInternal from "primate/s/internal";`
|
|
23
|
+
: "";
|
|
24
|
+
const i18n_setup = i18n_active ?
|
|
25
|
+
`if (this.#p.request.context.i18n.locale) {
|
|
26
|
+
t[sInternal].init(this.#p.request.context.i18n.locale);
|
|
27
|
+
}
|
|
28
|
+
this.#off = t.subscribe(() => this.#cdr.markForCheck());
|
|
29
|
+
`
|
|
30
|
+
: "";
|
|
31
|
+
return `
|
|
32
|
+
import {
|
|
33
|
+
Component,
|
|
34
|
+
Input,
|
|
35
|
+
inject,
|
|
36
|
+
ChangeDetectorRef,
|
|
37
|
+
OnDestroy,
|
|
38
|
+
TemplateRef,
|
|
39
|
+
AfterViewInit,
|
|
40
|
+
} from "@angular/core";
|
|
41
|
+
import { CommonModule, NgComponentOutlet } from "@angular/common";
|
|
42
|
+
import INITIAL_PROPS from "@primate/angular/INITIAL_PROPS";
|
|
43
|
+
${i18n_imports}
|
|
44
|
+
|
|
45
|
+
type Dict = Record<string, any>;
|
|
46
|
+
type RootProps = {
|
|
47
|
+
components: any[];
|
|
48
|
+
props: Dict[];
|
|
49
|
+
request: any;
|
|
50
|
+
update?: () => void
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
@Component({
|
|
54
|
+
standalone: true,
|
|
55
|
+
selector: "${root_selector}",
|
|
56
|
+
imports: [CommonModule, NgComponentOutlet],
|
|
57
|
+
template: \`<ng-container *ngIf="P as P">${body}</ng-container>\`
|
|
58
|
+
})
|
|
59
|
+
export default class RootComponent implements OnDestroy {
|
|
60
|
+
#p!: RootProps;
|
|
61
|
+
#cdr = inject(ChangeDetectorRef);
|
|
62
|
+
#off?: () => void;
|
|
63
|
+
|
|
64
|
+
constructor() {
|
|
65
|
+
try {
|
|
66
|
+
const initial = inject<any>(INITIAL_PROPS);
|
|
67
|
+
if (initial) this.#p = initial;
|
|
68
|
+
} catch {}
|
|
69
|
+
${i18n_setup}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@Input({ required: true })
|
|
73
|
+
set p(value: RootProps) {
|
|
74
|
+
this.#p = value;
|
|
75
|
+
this.#cdr.markForCheck(); // root on default CD, zone ticks traverse
|
|
76
|
+
}
|
|
77
|
+
get p(): RootProps { return this.#p; }
|
|
78
|
+
get P(): RootProps { return this.#p; }
|
|
79
|
+
|
|
80
|
+
// is there a component at index i?
|
|
81
|
+
has(i: number) { return !!this.P?.components?.[i]; }
|
|
82
|
+
|
|
83
|
+
// component type for index i
|
|
84
|
+
comp(i: number) { return this.P?.components?.[i]; }
|
|
85
|
+
|
|
86
|
+
// per-layer inputs without slot
|
|
87
|
+
inputs(i: number) {
|
|
88
|
+
return (this.P?.props?.[i] ?? {}) as Dict;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// per-layer inputs + slot template (only used when has(i+1) is true)
|
|
92
|
+
slotInputs(i: number, slot: TemplateRef<unknown>) {
|
|
93
|
+
const base = (this.P?.props?.[i] ?? {}) as Dict;
|
|
94
|
+
return { ...base, slot };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
ngAfterViewInit() {
|
|
98
|
+
t[sInternal].restore();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
ngOnDestroy() { this.#off?.(); }
|
|
102
|
+
}
|
|
103
|
+
`;
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=create-root.js.map
|
package/package.json
CHANGED
|
@@ -1,62 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/angular",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Primate Angular frontend",
|
|
5
|
-
"homepage": "https://
|
|
6
|
-
"bugs": "https://github.com/
|
|
5
|
+
"homepage": "https://primate.run/docs/frontend/angular",
|
|
6
|
+
"bugs": "https://github.com/primate-run/primate/issues",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"files": [
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"/lib/**/*.js",
|
|
10
|
+
"/lib/**/*.d.ts",
|
|
11
|
+
"!/**/*.spec.*"
|
|
11
12
|
],
|
|
12
13
|
"repository": {
|
|
13
14
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/primate-run/primate",
|
|
15
16
|
"directory": "packages/angular"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@angular/
|
|
19
|
-
"@angular/
|
|
20
|
-
"@angular/
|
|
21
|
-
"@angular/
|
|
22
|
-
"@
|
|
23
|
-
"@
|
|
24
|
-
"@rcompat/
|
|
25
|
-
"@rcompat/
|
|
26
|
-
"
|
|
27
|
-
"@
|
|
19
|
+
"@angular/common": "^20.3.2",
|
|
20
|
+
"@angular/compiler": "^20.3.2",
|
|
21
|
+
"@angular/core": "^20.3.2",
|
|
22
|
+
"@angular/platform-browser": "^20.3.2",
|
|
23
|
+
"@angular/platform-server": "^20.3.2",
|
|
24
|
+
"@angular/ssr": "^20.3.3",
|
|
25
|
+
"@rcompat/assert": "^0.3.1",
|
|
26
|
+
"@rcompat/build": "^0.14.0",
|
|
27
|
+
"@rcompat/crypto": "^0.10.0",
|
|
28
|
+
"@rcompat/fs": "^0.21.1",
|
|
29
|
+
"@rcompat/record": "^0.9.1",
|
|
30
|
+
"typescript": "^5.9.2",
|
|
31
|
+
"zone.js": "^0.15.1",
|
|
32
|
+
"@primate/core": "^0.2.1"
|
|
28
33
|
},
|
|
29
34
|
"peerDependencies": {
|
|
30
|
-
"
|
|
31
|
-
"primate": "^0.32.6"
|
|
35
|
+
"primate": "^0.33.1"
|
|
32
36
|
},
|
|
33
37
|
"type": "module",
|
|
34
38
|
"imports": {
|
|
35
39
|
"#*": {
|
|
36
|
-
"
|
|
37
|
-
"default": "./
|
|
38
|
-
},
|
|
39
|
-
"#build": {
|
|
40
|
-
"livetypes": "./src/private/build/index.js",
|
|
41
|
-
"default": "./src/private/build/index.js"
|
|
42
|
-
},
|
|
43
|
-
"#serve": {
|
|
44
|
-
"livetypes": "./src/private/serve/index.js",
|
|
45
|
-
"default": "./src/private/serve/index.js"
|
|
46
|
-
},
|
|
47
|
-
"#client": {
|
|
48
|
-
"livetypes": "./src/private/client/index.js",
|
|
49
|
-
"default": "./src/private/client/index.js"
|
|
50
|
-
},
|
|
51
|
-
"#client/*": {
|
|
52
|
-
"livetypes": "./src/private/client/*.js",
|
|
53
|
-
"default": "./src/private/client/*.js"
|
|
40
|
+
"apekit": "./src/private/*.ts",
|
|
41
|
+
"default": "./lib/private/*.js"
|
|
54
42
|
}
|
|
55
43
|
},
|
|
56
44
|
"exports": {
|
|
57
45
|
".": {
|
|
58
|
-
"
|
|
59
|
-
"
|
|
46
|
+
"browser": "./lib/public/browser.js",
|
|
47
|
+
"runtime": "./lib/public/runtime.js",
|
|
48
|
+
"default": "./lib/public/default.js"
|
|
49
|
+
},
|
|
50
|
+
"./*": {
|
|
51
|
+
"apekit": "./src/public/*.ts",
|
|
52
|
+
"default": "./lib/public/*.js"
|
|
60
53
|
}
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "npm run clean && tsc",
|
|
57
|
+
"clean": "rm -rf ./lib",
|
|
58
|
+
"lint": "eslint ."
|
|
61
59
|
}
|
|
62
60
|
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import normalize from "#normalize";
|
|
2
|
-
|
|
3
|
-
export default async (app, component) => {
|
|
4
|
-
const location = app.get("location");
|
|
5
|
-
const source = app.runpath(location.components);
|
|
6
|
-
const { path } = component.debase(source, "/");
|
|
7
|
-
|
|
8
|
-
const code = `export { default as ${await normalize(path)} } from
|
|
9
|
-
"./${location.components}/${path}";`;
|
|
10
|
-
app.build.export(code);
|
|
11
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import create_root from "#client/create-root-client";
|
|
2
|
-
import expose from "#client/expose";
|
|
3
|
-
import name from "#name";
|
|
4
|
-
import client from "./client.js";
|
|
5
|
-
import publish from "./publish.js";
|
|
6
|
-
import server from "./server.js";
|
|
7
|
-
|
|
8
|
-
const client_root = async app => {
|
|
9
|
-
const root = create_root();
|
|
10
|
-
const code = `export { default as root_${name} } from "root:${name}";`;
|
|
11
|
-
app.build.save(`root:${name}`, root);
|
|
12
|
-
app.build.export(code);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export default extension => async (app, next) => {
|
|
16
|
-
const extensions = {
|
|
17
|
-
from: extension,
|
|
18
|
-
to: ".js",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
app.register(extension, {
|
|
22
|
-
server: component => server(app, component, extensions),
|
|
23
|
-
client: component => client(app, component, extensions),
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
await client_root(app);
|
|
27
|
-
app.build.plugin(publish(app, extension));
|
|
28
|
-
app.build.export(expose);
|
|
29
|
-
|
|
30
|
-
return next(app);
|
|
31
|
-
};
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import file from "@rcompat/fs/file";
|
|
2
|
-
import compile from "./compile.js";
|
|
3
|
-
import name from "#name";
|
|
4
|
-
|
|
5
|
-
const root_filter = /^root:angular/u;
|
|
6
|
-
|
|
7
|
-
export default (app, extension) => ({
|
|
8
|
-
name,
|
|
9
|
-
setup(build) {
|
|
10
|
-
const resolveDir = app.path.build.path;
|
|
11
|
-
|
|
12
|
-
build.onResolve({ filter: root_filter }, ({ path }) => {
|
|
13
|
-
return { path, namespace: `${name}-root` };
|
|
14
|
-
});
|
|
15
|
-
build.onLoad({ filter: root_filter }, ({ path }) => {
|
|
16
|
-
const contents = app.build.load(path);
|
|
17
|
-
return contents ? { contents, loader: "js", resolveDir } : null;
|
|
18
|
-
});
|
|
19
|
-
build.onLoad({ filter: new RegExp(`${extension}$`, "u") }, async args => {
|
|
20
|
-
// Load the file from the file system
|
|
21
|
-
const source = await file(args.path).text();
|
|
22
|
-
|
|
23
|
-
// Compile component.ts file to JavaScript
|
|
24
|
-
return { contents: await compile(source) };
|
|
25
|
-
});
|
|
26
|
-
},
|
|
27
|
-
});
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import compile from "./compile.js";
|
|
2
|
-
|
|
3
|
-
export default async (app, component, extensions) => {
|
|
4
|
-
const location = app.get("location");
|
|
5
|
-
const source = app.runpath(location.components);
|
|
6
|
-
const code = await compile(await component.text());
|
|
7
|
-
const target_base = app.runpath(location.server, location.components);
|
|
8
|
-
const path = target_base.join(`${component.path}.js`.replace(source, ""));
|
|
9
|
-
await path.directory.create();
|
|
10
|
-
await path.write(code.replaceAll(extensions.from, extensions.to));
|
|
11
|
-
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export default () => `
|
|
3
|
-
import { Component, reflectComponentType } from "@angular/core";
|
|
4
|
-
import stringify from "@rcompat/object/stringify";
|
|
5
|
-
|
|
6
|
-
const root_component = ({ template, imports }) => Component({
|
|
7
|
-
selector: "app-root",
|
|
8
|
-
imports,
|
|
9
|
-
template,
|
|
10
|
-
standalone: true,
|
|
11
|
-
})(class {});
|
|
12
|
-
const double_to_single = string => string.replaceAll('"', "'");
|
|
13
|
-
|
|
14
|
-
export default (component, props) => {
|
|
15
|
-
const { selector } = reflectComponentType(component);
|
|
16
|
-
const attributes = Object.entries(props)
|
|
17
|
-
.map(([key, value]) => \`[\${key}]="\${double_to_single(stringify(value))}"\`)
|
|
18
|
-
.join(" ");
|
|
19
|
-
|
|
20
|
-
return root_component({
|
|
21
|
-
imports: [component],
|
|
22
|
-
template: \`<\${selector} \${attributes}></\${selector}>\`,
|
|
23
|
-
});
|
|
24
|
-
};`;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import root_selector from "#client/root-selector";
|
|
2
|
-
import { Component, reflectComponentType } from "@angular/core";
|
|
3
|
-
import stringify from "@rcompat/object/stringify";
|
|
4
|
-
|
|
5
|
-
const root_component = ({ template, imports }) => Component({
|
|
6
|
-
selector: root_selector,
|
|
7
|
-
imports,
|
|
8
|
-
template,
|
|
9
|
-
standalone: true,
|
|
10
|
-
})(class {});
|
|
11
|
-
|
|
12
|
-
const double_to_single = string => string.replaceAll("\"", "'");
|
|
13
|
-
|
|
14
|
-
export default (component, props) => {
|
|
15
|
-
const { selector } = reflectComponentType(component);
|
|
16
|
-
const attributes = Object.entries(props)
|
|
17
|
-
.map(([key, value]) => `[${key}]="${double_to_single(stringify(value))}"`)
|
|
18
|
-
.join(" ");
|
|
19
|
-
|
|
20
|
-
return root_component({
|
|
21
|
-
imports: [component],
|
|
22
|
-
template: `<${selector} ${attributes}></${selector}>`,
|
|
23
|
-
});
|
|
24
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export default ({ component, props }) => `
|
|
2
|
-
import { bootstrapApplication, provideClientHydration } from "app";
|
|
3
|
-
import * as components from "app";
|
|
4
|
-
|
|
5
|
-
const config = { providers: [provideClientHydration()] };
|
|
6
|
-
|
|
7
|
-
const rendered = components.root_angular(components.${component},
|
|
8
|
-
${JSON.stringify(props)});
|
|
9
|
-
|
|
10
|
-
bootstrapApplication(rendered, config)
|
|
11
|
-
.catch(error => console.error(error));`;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default "app-root";
|
package/src/private/extension.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default ".component.ts";
|
package/src/private/name.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default "angular";
|
package/src/private/normalize.js
DELETED
package/src/private/pkgname.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export default "@primate/angular";
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import render from "./render.js";
|
|
2
|
-
import set_mode from "./set-mode.js";
|
|
3
|
-
import client from "#client";
|
|
4
|
-
import normalize from "#normalize";
|
|
5
|
-
|
|
6
|
-
const serve = (name, props = {}, options = {}) => async app => {
|
|
7
|
-
const component = await app.get_component(name);
|
|
8
|
-
|
|
9
|
-
const normalized = await normalize(name);
|
|
10
|
-
const code = client({ component: normalized, props });
|
|
11
|
-
const inlined = await app.inline(code, "module");
|
|
12
|
-
const script_src = [inlined.integrity];
|
|
13
|
-
|
|
14
|
-
return app.view({
|
|
15
|
-
body: await render(component, props),
|
|
16
|
-
head: inlined.head,
|
|
17
|
-
headers: app.headers({ "script-src": script_src }),
|
|
18
|
-
...options,
|
|
19
|
-
});
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export default extension => (app, next) => {
|
|
23
|
-
// todo: base on app mode
|
|
24
|
-
set_mode("production");
|
|
25
|
-
|
|
26
|
-
app.register(extension, serve);
|
|
27
|
-
|
|
28
|
-
return next(app);
|
|
29
|
-
};
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import "@angular/compiler";
|
|
2
|
-
import {
|
|
3
|
-
bootstrapApplication,
|
|
4
|
-
provideClientHydration,
|
|
5
|
-
} from "@angular/platform-browser";
|
|
6
|
-
import {
|
|
7
|
-
provideServerRendering,
|
|
8
|
-
ɵSERVER_CONTEXT,
|
|
9
|
-
} from "@angular/platform-server";
|
|
10
|
-
import { CommonEngine } from "@angular/ssr";
|
|
11
|
-
import "zone.js";
|
|
12
|
-
import create_root from "#client/create-root";
|
|
13
|
-
import root_selector from "#client/root-selector";
|
|
14
|
-
|
|
15
|
-
const common_engine = new CommonEngine();
|
|
16
|
-
|
|
17
|
-
export default async (given_component, props) => {
|
|
18
|
-
const component = create_root(given_component, props);
|
|
19
|
-
const document = `<${root_selector}></${root_selector}>`;
|
|
20
|
-
const bootstrap = () => bootstrapApplication(component, {
|
|
21
|
-
providers: [
|
|
22
|
-
provideServerRendering(),
|
|
23
|
-
{ provide: ɵSERVER_CONTEXT, useValue: "analog" },
|
|
24
|
-
...component.renderProviders || [],
|
|
25
|
-
provideClientHydration(),
|
|
26
|
-
],
|
|
27
|
-
});
|
|
28
|
-
const b_s = "<body>";
|
|
29
|
-
const b_e = "</body>";
|
|
30
|
-
const html = await common_engine.render({ bootstrap, document });
|
|
31
|
-
|
|
32
|
-
return html.slice(html.indexOf(b_s) + b_s.length, html.indexOf(b_e));
|
|
33
|
-
};
|
package/src/public/default.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import build from "#build";
|
|
2
|
-
import default_extension from "#extension";
|
|
3
|
-
import pkgname from "#pkgname";
|
|
4
|
-
import serve from "#serve";
|
|
5
|
-
|
|
6
|
-
export default ({ extension = default_extension } = {}) => ({
|
|
7
|
-
name: pkgname,
|
|
8
|
-
build: build(extension),
|
|
9
|
-
serve: serve(extension),
|
|
10
|
-
});
|