Skip to content

Commit 0a9df55

Browse files
committed
WIP
1 parent a40f89e commit 0a9df55

File tree

8 files changed

+1884
-77
lines changed

8 files changed

+1884
-77
lines changed

packages/runtime/src/internal/fulfilStoryboard.ts

Lines changed: 92 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,23 @@ import type {
33
BrickEventHandler,
44
BrickEventsMap,
55
BuiltinBrickEventHandler,
6-
RouteConf,
76
RouteConfOfBricks,
87
RuntimeStoryboard,
8+
Storyboard,
99
} from "@next-core/types";
1010
import { isEvaluable } from "@next-core/cook";
11+
import { hasOwnProperty } from "@next-core/utils/general";
12+
import {
13+
parseStoryboard,
14+
traverse,
15+
parseEvents,
16+
type StoryboardNodeEvent,
17+
type StoryboardNodeRoute,
18+
} from "@next-core/utils/storyboard";
1119
import { uniqueId } from "lodash";
1220
import { hooks } from "./Runtime.js";
1321
import { registerAppI18n } from "./registerAppI18n.js";
14-
import { isBuiltinHandler } from "./bindListeners.js";
22+
import { isBuiltinHandler, isCustomHandler } from "./bindListeners.js";
1523

1624
export async function fulfilStoryboard(storyboard: RuntimeStoryboard) {
1725
if (storyboard.$$fulfilled) {
@@ -26,70 +34,58 @@ export async function fulfilStoryboard(storyboard: RuntimeStoryboard) {
2634
async function doFulfilStoryboard(storyboard: RuntimeStoryboard) {
2735
await hooks?.fulfilStoryboard?.(storyboard);
2836
registerAppI18n(storyboard);
29-
initializeSeguesForRoutes(storyboard.routes);
37+
// initializeSeguesForRoutes(storyboard.routes);
38+
initializeSegues(storyboard);
3039
Object.assign(storyboard, {
3140
$$fulfilled: true,
3241
$$fulfilling: null,
3342
});
3443
}
3544

45+
type SceneConf = Pick<BrickConf, "properties" | "events">;
46+
3647
interface SegueConf {
37-
by: "drawer" | "modal";
48+
type: "drawer" | "modal";
3849
route?: {
3950
path: string;
40-
params: SegueRouteParam[];
51+
params: Record<string, string>;
4152
};
42-
eventsMapping?: Record<string, string>;
43-
events?: BrickEventsMap;
44-
}
45-
46-
interface SegueRouteParam {
47-
key: string;
48-
value: string;
53+
modal?: SceneConf;
54+
scene?: SceneConf;
4955
}
5056

51-
function initializeSeguesForRoutes(routes: RouteConf[]) {
52-
for (const route of routes) {
53-
if (route.type !== "redirect" && route.type !== "routes") {
54-
initializeSeguesForBricks(route.bricks, route);
55-
}
56-
}
57-
}
57+
function initializeSegues(storyboard: Storyboard) {
58+
const ast = parseStoryboard(storyboard);
5859

59-
function initializeSeguesForBricks(
60-
bricks: BrickConf[],
61-
routeParent: RouteConfOfBricks
62-
) {
63-
for (const brick of bricks) {
64-
if (brick.events) {
65-
for (const [eventType, handlers] of Object.entries(brick.events)) {
66-
if (Array.isArray(handlers)) {
67-
handlers.forEach((handler, index) => {
68-
if (isBuiltinHandler(handler) && handler.action === "segue.go") {
69-
replaceSegues(handler, handlers, index, routeParent);
70-
}
71-
});
72-
} else if (
73-
isBuiltinHandler(handlers) &&
74-
handlers.action === "segue.go"
75-
) {
76-
replaceSegues(handlers, brick.events, eventType, routeParent);
60+
traverse(ast, (node, nodePath) => {
61+
switch (node.type) {
62+
case "EventHandler":
63+
if (isBuiltinHandler(node.raw) && node.raw.action === "segue.go") {
64+
const parent = nodePath[nodePath.length - 1] as StoryboardNodeEvent;
65+
const routeParent = (
66+
nodePath.findLast(
67+
(node) => node.type === "Route" && node.raw.type === "bricks"
68+
) as StoryboardNodeRoute
69+
).raw as RouteConfOfBricks;
70+
if (typeof node.rawKey === "number") {
71+
replaceSegues(
72+
node.raw,
73+
parent.rawContainer[parent.rawKey] as BrickEventHandler[],
74+
node.rawKey,
75+
routeParent
76+
);
77+
} else {
78+
replaceSegues(
79+
node.raw,
80+
parent.rawContainer,
81+
parent.rawKey,
82+
routeParent
83+
);
84+
}
7785
}
78-
}
79-
}
80-
81-
if (brick.slots) {
82-
for (const slotConf of Object.values(brick.slots)) {
83-
if (slotConf.type === "routes") {
84-
initializeSeguesForRoutes(slotConf.routes);
85-
} else {
86-
initializeSeguesForBricks(slotConf.bricks, routeParent);
87-
}
88-
}
89-
} else if (Array.isArray(brick.children)) {
90-
initializeSeguesForBricks(brick.children, routeParent);
86+
break;
9187
}
92-
}
88+
});
9389
}
9490

9591
function replaceSegues(
@@ -106,17 +102,18 @@ function replaceSegues(
106102
typeof segueTarget === "string") &&
107103
(segueConf = handler.args[1] as SegueConf)
108104
) {
109-
switch (segueConf.by) {
105+
switch (segueConf.type) {
110106
case "drawer": {
111107
if (segueConf.route) {
112108
const { params, path } = segueConf.route;
113-
const targetUrlExpr = path.replace(/:(\w+)/g, (_, key) => {
114-
const param = params.find((param) => param.key === key);
115-
return param
116-
? typeof param.value === "string" && isEvaluable(param.value)
117-
? `\${${param.value.replace(/^\s*<%[~=]?\s|\s%>\s*$/g, "")}}`
118-
: String(param.value).replace(/[`\\]/g, "\\$&")
119-
: `\${PATH.${key}}`;
109+
const targetUrlExpr = path.replace(/:(\w+)/g, (_, k) => {
110+
const hasParam = hasOwnProperty(params, k);
111+
const paramValue = hasParam ? params[k] : undefined;
112+
return hasParam
113+
? typeof paramValue === "string" && isEvaluable(paramValue)
114+
? `\${${paramValue.replace(/^\s*<%[~=]?\s|\s%>\s*$/g, "")}}`
115+
: String(paramValue).replace(/[`\\]/g, "\\$&")
116+
: `\${PATH.${k}}`;
120117
});
121118
(handlers as BrickEventsMap)[key] = {
122119
action: "history.push",
@@ -126,6 +123,7 @@ function replaceSegues(
126123
const drawerTarget = `#${drawerId}`;
127124
routeParent.bricks.push({
128125
brick: "eo-drawer",
126+
iid: drawerId,
129127
portal: true,
130128
properties: {
131129
id: drawerId,
@@ -150,10 +148,7 @@ function replaceSegues(
150148
{
151149
brick: segueTarget,
152150
properties: Object.fromEntries(
153-
params.map((param) => [
154-
param.key,
155-
`<% PATH.${param.key} %>`,
156-
])
151+
Object.keys(params).map((k) => [k, `<% PATH.${k} %>`])
157152
),
158153
lifeCycle: {
159154
onMount: {
@@ -185,32 +180,33 @@ function replaceSegues(
185180
target: modalTarget,
186181
method: "open",
187182
};
183+
184+
const replacements = new Map<string, string>([
185+
["_modal", modalTarget],
186+
["_scene", sceneTarget],
187+
]);
188+
replaceSceneTarget(segueConf.modal?.events, replacements);
189+
replaceSceneTarget(segueConf.scene?.events, replacements);
190+
188191
routeParent.bricks.push({
189192
brick: "eo-modal",
193+
iid: modalId,
190194
portal: true,
191195
properties: {
192-
id: modalId,
193-
modalTitle: "Create",
194196
closeWhenConfirm: false,
197+
...segueConf.modal?.properties,
198+
id: modalId,
195199
},
196-
events: segueConf.eventsMapping
197-
? Object.fromEntries(
198-
Object.entries(segueConf.eventsMapping).map(([from, to]) => [
199-
from,
200-
{
201-
target: sceneTarget,
202-
method: to,
203-
},
204-
])
205-
)
206-
: undefined,
200+
events: segueConf.modal?.events,
207201
children: [
208202
{
209203
brick: segueTarget,
204+
iid: sceneId,
210205
properties: {
206+
...segueConf.scene?.properties,
211207
id: sceneId,
212208
},
213-
events: segueConf.events,
209+
events: segueConf.scene?.events,
214210
},
215211
],
216212
});
@@ -219,3 +215,22 @@ function replaceSegues(
219215
}
220216
}
221217
}
218+
219+
function replaceSceneTarget(
220+
events: BrickEventsMap | undefined,
221+
replacements: Map<string, string>
222+
) {
223+
const ast = parseEvents(events);
224+
225+
traverse(ast, (node) => {
226+
switch (node.type) {
227+
case "EventHandler":
228+
if (isCustomHandler(node.raw) && typeof node.raw.target === "string") {
229+
const replacement = replacements.get(node.raw.target);
230+
if (replacement !== undefined) {
231+
node.raw.target = replacement;
232+
}
233+
}
234+
}
235+
});
236+
}

packages/utils/src/storyboard/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ export {
88
/** @deprecated import it from "@next-core/utils/general" instead */
99
unwrapProvider,
1010
};
11+
export * from "./parser/index.js";
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { type ParseOptions, parseStoryboard, parseEvents } from "./parser.js";
2+
export * from "./interfaces.js";
3+
export * from "./traverse.js";

0 commit comments

Comments
 (0)