mapples 0.2.0-beta.3 → 0.2.0-beta.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/dist/api/objects.d.ts +3 -1
- package/dist/api/objects.js +24 -1
- package/dist/api/objects.js.map +1 -1
- package/dist/codegen/emit.d.ts +2 -31
- package/dist/codegen/emit.js +7 -147
- package/dist/codegen/emit.js.map +1 -1
- package/dist/codegen/imports.d.ts +1 -17
- package/dist/codegen/imports.js +2 -116
- package/dist/codegen/imports.js.map +1 -1
- package/dist/codegen/instances.d.ts +2 -13
- package/dist/codegen/instances.js +23 -134
- package/dist/codegen/instances.js.map +1 -1
- package/dist/codegen/styles.d.ts +1 -11
- package/dist/codegen/styles.js +2 -130
- package/dist/codegen/styles.js.map +1 -1
- package/dist/merge/threeWay.d.ts +1 -1
- package/dist/merge/toEdits.d.ts +1 -3
- package/dist/merge/toEdits.js +3 -94
- package/dist/merge/toEdits.js.map +1 -1
- package/dist/project/baseStore.d.ts +11 -1
- package/dist/project/baseStore.js +13 -0
- package/dist/project/baseStore.js.map +1 -1
- package/dist/services/syncEngine.d.ts +1 -1
- package/dist/services/syncEngine.js +260 -39
- package/dist/services/syncEngine.js.map +1 -1
- package/dist/types.d.ts +19 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
package/dist/api/objects.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Bootstrap, type RenderDomNode } from '../types.js';
|
|
1
|
+
import { type Bootstrap, type RenderDomNode, type SourceEntity } from '../types.js';
|
|
2
2
|
import type { JpatchClient } from './client.js';
|
|
3
3
|
export interface PageEntity {
|
|
4
4
|
id: string;
|
|
@@ -57,6 +57,8 @@ export interface ProjectState {
|
|
|
57
57
|
navigation: NavigationDocument;
|
|
58
58
|
style: StyleConfig;
|
|
59
59
|
assets: AssetIndex;
|
|
60
|
+
/** Stored source text per page/component id — only containers that have one. */
|
|
61
|
+
sources: Map<string, SourceEntity>;
|
|
60
62
|
}
|
|
61
63
|
/** Pages on the real backend carry no route; derive a stable one from the name. */
|
|
62
64
|
export declare function deriveRoute(name: string): string;
|
package/dist/api/objects.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from 'axios';
|
|
2
|
-
import { sidecarOf } from '../types.js';
|
|
2
|
+
import { sidecarOf, } from '../types.js';
|
|
3
3
|
// ---- Hash-linked blob resolution (RFC-0001 §4.1) ----
|
|
4
4
|
// The real backend embeds children as hash STRINGS, never inlined: a page blob
|
|
5
5
|
// is {id, name, root: "b3:…"} and a node blob is {id, key?, type, props,
|
|
@@ -159,8 +159,31 @@ export async function fetchProjectState(client, boot) {
|
|
|
159
159
|
navigation: navigationBlob,
|
|
160
160
|
style,
|
|
161
161
|
assets,
|
|
162
|
+
sources: await fetchSources(client, boot),
|
|
162
163
|
};
|
|
163
164
|
}
|
|
165
|
+
/** The `sources` index (RFC-0001 A12), keyed by container id; empty when the manifest has none. */
|
|
166
|
+
async function fetchSources(client, boot) {
|
|
167
|
+
const sources = new Map();
|
|
168
|
+
if (boot.manifest.sources === undefined)
|
|
169
|
+
return sources;
|
|
170
|
+
const index = (await client.getObject(boot.manifest.sources));
|
|
171
|
+
const blobs = await fetchObjects(client, Object.values(index));
|
|
172
|
+
for (const [indexId, hash] of Object.entries(index)) {
|
|
173
|
+
const blob = blobs.get(hash);
|
|
174
|
+
if (typeof blob.of !== 'string' || typeof blob.text !== 'string') {
|
|
175
|
+
throw new Error(`source blob ${indexId} is missing of/text — schema drift, update the CLI`);
|
|
176
|
+
}
|
|
177
|
+
sources.set(blob.of, {
|
|
178
|
+
id: blob.id ?? indexId,
|
|
179
|
+
of: blob.of,
|
|
180
|
+
lang: typeof blob.lang === 'string' ? blob.lang : 'tsx',
|
|
181
|
+
text: blob.text,
|
|
182
|
+
...(typeof blob.docHash === 'string' ? { docHash: blob.docHash } : {}),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return sources;
|
|
186
|
+
}
|
|
164
187
|
/**
|
|
165
188
|
* Upload binary asset bodies: `objects/have` filters to genuinely missing
|
|
166
189
|
* hashes, then PUT bytes to each signed URL (RFC-0001 §6, binary assets).
|
package/dist/api/objects.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objects.js","sourceRoot":"","sources":["../../src/api/objects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,
|
|
1
|
+
{"version":3,"file":"objects.js","sourceRoot":"","sources":["../../src/api/objects.ts"],"names":[],"mappings":"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"}
|
package/dist/codegen/emit.d.ts
CHANGED
|
@@ -1,34 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
export
|
|
3
|
-
/** `// mapples-route: <id> — “<name>”` — the first such line names the route a file renders. */
|
|
4
|
-
export declare const ROUTE_MARKER: RegExp;
|
|
5
|
-
export declare function routeMarkerLine(routeId: string, routeName: string): string;
|
|
6
|
-
export declare function readRouteMarker(source: string): string | null;
|
|
7
|
-
/** Ensure `source` opens with the marker for `routeId`; replaces a stale marker, never duplicates. */
|
|
8
|
-
export declare function withRouteMarker(source: string, routeId: string, routeName: string): string;
|
|
9
|
-
export declare function withoutRouteMarker(source: string): string;
|
|
10
|
-
/**
|
|
11
|
-
* The exported component name for a page: the page name in PascalCase, with
|
|
12
|
-
* no suffix. `taken` lists identifiers the file already imports (a page named
|
|
13
|
-
* “View” must not shadow the `View` it renders) — a collision gets `Screen`.
|
|
14
|
-
*/
|
|
15
|
-
export declare function pageComponentName(pageName: string, taken?: Iterable<string>,
|
|
16
|
-
/** Appended when the name is taken or reserved: a page becomes `…Screen`, a component `…Component`. */
|
|
17
|
-
suffix?: 'Screen' | 'Component'): string;
|
|
18
|
-
export interface EmitPageInput {
|
|
19
|
-
name: string;
|
|
20
|
-
root: RenderDomNode;
|
|
21
|
-
/** Present for a routed page: the file opens with its route marker. */
|
|
22
|
-
route?: {
|
|
23
|
-
id: string;
|
|
24
|
-
name: string;
|
|
25
|
-
};
|
|
26
|
-
}
|
|
1
|
+
import { type EmitComponentInput, type EmitPageInput } from '@mapples/codegen';
|
|
2
|
+
export { COMPONENT_HEADER, GENERATED_HEADER, pageComponentName, readRouteMarker, ROUTE_MARKER, routeMarkerLine, withoutRouteMarker, withRouteMarker, type EmitComponentInput, type EmitPageInput, } from '@mapples/codegen';
|
|
27
3
|
export declare function emitPage(page: EmitPageInput, filePath?: string): Promise<string>;
|
|
28
|
-
export declare const COMPONENT_HEADER: string;
|
|
29
|
-
export interface EmitComponentInput {
|
|
30
|
-
name: string;
|
|
31
|
-
root: RenderDomNode;
|
|
32
|
-
}
|
|
33
4
|
/** A Creator component as a file: same shape as a page, no route. */
|
|
34
5
|
export declare function emitComponent(component: EmitComponentInput, filePath?: string): Promise<string>;
|
package/dist/codegen/emit.js
CHANGED
|
@@ -1,154 +1,14 @@
|
|
|
1
|
-
// RenderDom page -> complete page file
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
// layout): `app/<segment>.tsx` for a routed page, `<pagesDir>/<Name>.tsx` for
|
|
6
|
-
// a page that is not in the navigation yet. Routed files open with a route
|
|
7
|
-
// marker line that carries the route id — the file's identity for renames.
|
|
8
|
-
import { printNode, printValue } from '@mapples/sid-ast';
|
|
9
|
-
import { collectImports, printImports } from './imports.js';
|
|
1
|
+
// RenderDom page -> complete page file, Prettier-formatted with the target
|
|
2
|
+
// project's config. The generation itself lives in @mapples/codegen (pure),
|
|
3
|
+
// shared with the Creator's code editor; this module adds the formatting.
|
|
4
|
+
import { emitComponent as emitComponentText, emitPage as emitPageText, } from '@mapples/codegen';
|
|
10
5
|
import { formatTsx } from './format.js';
|
|
11
|
-
|
|
12
|
-
export const GENERATED_HEADER = '// Generated by Mapples — edit freely, but keep the $sid props intact.\n' +
|
|
13
|
-
'// Two-way sync: `mapples sync` reconciles this file with Mapples Creator.';
|
|
14
|
-
/** `// mapples-route: <id> — “<name>”` — the first such line names the route a file renders. */
|
|
15
|
-
export const ROUTE_MARKER = /\/\/\s*mapples-route:\s*([A-Za-z0-9_-]+)/;
|
|
16
|
-
export function routeMarkerLine(routeId, routeName) {
|
|
17
|
-
return `// mapples-route: ${routeId} — “${routeName}”. Renaming this file renames the route in Creator on the next \`mapples sync\`.`;
|
|
18
|
-
}
|
|
19
|
-
export function readRouteMarker(source) {
|
|
20
|
-
return ROUTE_MARKER.exec(source)?.[1] ?? null;
|
|
21
|
-
}
|
|
22
|
-
/** Ensure `source` opens with the marker for `routeId`; replaces a stale marker, never duplicates. */
|
|
23
|
-
export function withRouteMarker(source, routeId, routeName) {
|
|
24
|
-
const line = routeMarkerLine(routeId, routeName);
|
|
25
|
-
const lines = source.split('\n');
|
|
26
|
-
const idx = lines.findIndex((l) => ROUTE_MARKER.test(l));
|
|
27
|
-
if (idx === -1)
|
|
28
|
-
return `${line}\n${source}`;
|
|
29
|
-
if (lines[idx] === line)
|
|
30
|
-
return source;
|
|
31
|
-
lines[idx] = line;
|
|
32
|
-
return lines.join('\n');
|
|
33
|
-
}
|
|
34
|
-
export function withoutRouteMarker(source) {
|
|
35
|
-
const lines = source.split('\n');
|
|
36
|
-
const idx = lines.findIndex((l) => ROUTE_MARKER.test(l));
|
|
37
|
-
if (idx === -1)
|
|
38
|
-
return source;
|
|
39
|
-
lines.splice(idx, 1);
|
|
40
|
-
// A marker was followed by its own blank line; drop it so the file does not grow a gap.
|
|
41
|
-
if (idx === 0 && lines[0] === '')
|
|
42
|
-
lines.shift();
|
|
43
|
-
return lines.join('\n');
|
|
44
|
-
}
|
|
45
|
-
const RESERVED = new Set([
|
|
46
|
-
'default',
|
|
47
|
-
'function',
|
|
48
|
-
'class',
|
|
49
|
-
'return',
|
|
50
|
-
'export',
|
|
51
|
-
'import',
|
|
52
|
-
'new',
|
|
53
|
-
'delete',
|
|
54
|
-
'in',
|
|
55
|
-
'of',
|
|
56
|
-
'for',
|
|
57
|
-
'if',
|
|
58
|
-
'else',
|
|
59
|
-
'switch',
|
|
60
|
-
'case',
|
|
61
|
-
'while',
|
|
62
|
-
'do',
|
|
63
|
-
'var',
|
|
64
|
-
'let',
|
|
65
|
-
'const',
|
|
66
|
-
'this',
|
|
67
|
-
'super',
|
|
68
|
-
'null',
|
|
69
|
-
'true',
|
|
70
|
-
'false',
|
|
71
|
-
'void',
|
|
72
|
-
'typeof',
|
|
73
|
-
'with',
|
|
74
|
-
'yield',
|
|
75
|
-
'await',
|
|
76
|
-
'enum',
|
|
77
|
-
'extends',
|
|
78
|
-
'try',
|
|
79
|
-
'catch',
|
|
80
|
-
'finally',
|
|
81
|
-
'throw',
|
|
82
|
-
'break',
|
|
83
|
-
'continue',
|
|
84
|
-
'debugger',
|
|
85
|
-
'instanceof',
|
|
86
|
-
'static',
|
|
87
|
-
'interface',
|
|
88
|
-
'package',
|
|
89
|
-
'private',
|
|
90
|
-
'protected',
|
|
91
|
-
'public',
|
|
92
|
-
'implements',
|
|
93
|
-
]);
|
|
94
|
-
/**
|
|
95
|
-
* The exported component name for a page: the page name in PascalCase, with
|
|
96
|
-
* no suffix. `taken` lists identifiers the file already imports (a page named
|
|
97
|
-
* “View” must not shadow the `View` it renders) — a collision gets `Screen`.
|
|
98
|
-
*/
|
|
99
|
-
export function pageComponentName(pageName, taken = [],
|
|
100
|
-
/** Appended when the name is taken or reserved: a page becomes `…Screen`, a component `…Component`. */
|
|
101
|
-
suffix = 'Screen') {
|
|
102
|
-
let pascal = pageName
|
|
103
|
-
.split(/[^A-Za-z0-9]+/)
|
|
104
|
-
.filter(Boolean)
|
|
105
|
-
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
106
|
-
.join('');
|
|
107
|
-
if (pascal === '' || /^[0-9]/.test(pascal))
|
|
108
|
-
pascal = `Page${pascal}`;
|
|
109
|
-
const used = new Set(taken);
|
|
110
|
-
if (used.has(pascal) || RESERVED.has(pascal.toLowerCase()))
|
|
111
|
-
pascal = `${pascal}${suffix}`;
|
|
112
|
-
return pascal;
|
|
113
|
-
}
|
|
6
|
+
export { COMPONENT_HEADER, GENERATED_HEADER, pageComponentName, readRouteMarker, ROUTE_MARKER, routeMarkerLine, withoutRouteMarker, withRouteMarker, } from '@mapples/codegen';
|
|
114
7
|
export async function emitPage(page, filePath) {
|
|
115
|
-
return
|
|
8
|
+
return formatTsx(emitPageText(page), filePath);
|
|
116
9
|
}
|
|
117
|
-
export const COMPONENT_HEADER = '// Generated by Mapples — a Creator component. Edit freely, keep the $sid props intact.\n' +
|
|
118
|
-
'// Two-way sync: `mapples sync` reconciles this file with Mapples Creator.';
|
|
119
10
|
/** A Creator component as a file: same shape as a page, no route. */
|
|
120
11
|
export async function emitComponent(component, filePath) {
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
async function emitTree(name, root, leading, filePath, header = GENERATED_HEADER, suffix = 'Screen') {
|
|
124
|
-
const imports = collectImports(root);
|
|
125
|
-
// Styles live in a `Styler.create` dictionary below the component, the way
|
|
126
|
-
// hand-written Mapples code keeps them — never inline in the JSX.
|
|
127
|
-
const styles = hoistStyles(root);
|
|
128
|
-
const jsx = printNode(root, ' ', { styleRef: styles.refFor });
|
|
129
|
-
const componentName = pageComponentName(name, [...imports.uiNames, ...imports.customs.keys(), styles.dictName, 'Styler'], suffix);
|
|
130
|
-
const code = [
|
|
131
|
-
...leading,
|
|
132
|
-
header,
|
|
133
|
-
'',
|
|
134
|
-
printImports(imports),
|
|
135
|
-
...(styles.entries.length > 0 ? [`import { Styler } from '${STYLE_MODULE}';`] : []),
|
|
136
|
-
'',
|
|
137
|
-
`export default function ${componentName}() {`,
|
|
138
|
-
' return (',
|
|
139
|
-
jsx,
|
|
140
|
-
' );',
|
|
141
|
-
'}',
|
|
142
|
-
...(styles.entries.length > 0
|
|
143
|
-
? [
|
|
144
|
-
'',
|
|
145
|
-
`const ${styles.dictName} = Styler.create({`,
|
|
146
|
-
...styles.entries.map(([key, value]) => ` ${key}: ${printValue(value)},`),
|
|
147
|
-
'});',
|
|
148
|
-
]
|
|
149
|
-
: []),
|
|
150
|
-
'',
|
|
151
|
-
].join('\n');
|
|
152
|
-
return formatTsx(code, filePath);
|
|
12
|
+
return formatTsx(emitComponentText(component), filePath);
|
|
153
13
|
}
|
|
154
14
|
//# sourceMappingURL=emit.js.map
|
package/dist/codegen/emit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/codegen/emit.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"emit.js","sourceRoot":"","sources":["../../src/codegen/emit.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,0EAA0E;AAE1E,OAAO,EACL,aAAa,IAAI,iBAAiB,EAClC,QAAQ,IAAI,YAAY,GAGzB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,eAAe,GAGhB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAmB,EAAE,QAAiB;IACnE,OAAO,SAAS,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AACjD,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,SAA6B,EAC7B,QAAiB;IAEjB,OAAO,SAAS,CAAC,iBAAiB,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -1,17 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export interface ResolvedImports {
|
|
3
|
-
uiNames: string[];
|
|
4
|
-
customs: Map<string, {
|
|
5
|
-
module: string;
|
|
6
|
-
exportName: string;
|
|
7
|
-
}>;
|
|
8
|
-
}
|
|
9
|
-
export declare const UI_MODULE = "@mapples/ui";
|
|
10
|
-
export declare function parseImportRef(ref: string): {
|
|
11
|
-
module: string;
|
|
12
|
-
exportName: string;
|
|
13
|
-
};
|
|
14
|
-
export declare function collectImports(root: RenderDomNode): ResolvedImports;
|
|
15
|
-
export declare function printImports(resolved: ResolvedImports): string;
|
|
16
|
-
/** ImportNeeds for @mapples/sid-ast upsertImports, from a merged tree. */
|
|
17
|
-
export declare function importNeedsFor(root: import('../types.js').RenderDomNode): import('@mapples/sid-ast').ImportNeed[];
|
|
1
|
+
export { collectImports, importNeedsFor, parseImportRef, printImports, UI_MODULE, type ResolvedImports, } from '@mapples/codegen';
|
package/dist/codegen/imports.js
CHANGED
|
@@ -1,117 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
const idx = ref.lastIndexOf('#');
|
|
4
|
-
if (idx === -1)
|
|
5
|
-
throw new Error(`invalid importRef (missing #): ${ref}`);
|
|
6
|
-
return { module: ref.slice(0, idx), exportName: ref.slice(idx + 1) };
|
|
7
|
-
}
|
|
8
|
-
export function collectImports(root) {
|
|
9
|
-
const uiNames = new Set();
|
|
10
|
-
const customs = new Map();
|
|
11
|
-
const walk = (node) => {
|
|
12
|
-
if (node.type === 'Custom') {
|
|
13
|
-
const name = node.props.name;
|
|
14
|
-
const importRef = node.props.importRef;
|
|
15
|
-
if (typeof name !== 'string' || typeof importRef !== 'string') {
|
|
16
|
-
throw new Error(`Custom node ${node.sid} is missing name/importRef`);
|
|
17
|
-
}
|
|
18
|
-
const origin = parseImportRef(importRef);
|
|
19
|
-
if (origin.module === '') {
|
|
20
|
-
throw new Error(`Custom node ${node.sid} (${name}) has a local importRef (${importRef}); cannot emit an import for it`);
|
|
21
|
-
}
|
|
22
|
-
const existing = customs.get(name);
|
|
23
|
-
if (existing &&
|
|
24
|
-
(existing.module !== origin.module || existing.exportName !== origin.exportName)) {
|
|
25
|
-
throw new Error(`Custom name collision: ${name} maps to both ${existing.module} and ${origin.module}`);
|
|
26
|
-
}
|
|
27
|
-
customs.set(name, origin);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
uiNames.add(node.type);
|
|
31
|
-
}
|
|
32
|
-
for (const child of node.children)
|
|
33
|
-
walk(child);
|
|
34
|
-
};
|
|
35
|
-
walk(root);
|
|
36
|
-
for (const name of customs.keys()) {
|
|
37
|
-
if (uiNames.has(name)) {
|
|
38
|
-
throw new Error(`Custom component ${name} collides with a @mapples/ui primitive of the same name`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return { uiNames: [...uiNames].sort(), customs };
|
|
42
|
-
}
|
|
43
|
-
export function printImports(resolved) {
|
|
44
|
-
const lines = [];
|
|
45
|
-
if (resolved.uiNames.length > 0) {
|
|
46
|
-
lines.push(`import { ${resolved.uiNames.join(', ')} } from '${UI_MODULE}';`);
|
|
47
|
-
}
|
|
48
|
-
const byModule = new Map();
|
|
49
|
-
for (const [local, origin] of resolved.customs) {
|
|
50
|
-
let entry = byModule.get(origin.module);
|
|
51
|
-
if (!entry) {
|
|
52
|
-
entry = { defaults: [], named: [] };
|
|
53
|
-
byModule.set(origin.module, entry);
|
|
54
|
-
}
|
|
55
|
-
if (origin.exportName === 'default')
|
|
56
|
-
entry.defaults.push(local);
|
|
57
|
-
else
|
|
58
|
-
entry.named.push([origin.exportName, local]);
|
|
59
|
-
}
|
|
60
|
-
for (const module of [...byModule.keys()].sort()) {
|
|
61
|
-
const entry = byModule.get(module);
|
|
62
|
-
const pieces = [];
|
|
63
|
-
if (entry.defaults.length > 1) {
|
|
64
|
-
throw new Error(`two default imports from ${module}: ${entry.defaults.join(', ')}`);
|
|
65
|
-
}
|
|
66
|
-
if (entry.defaults.length === 1)
|
|
67
|
-
pieces.push(entry.defaults[0]);
|
|
68
|
-
if (entry.named.length > 0) {
|
|
69
|
-
const named = entry.named
|
|
70
|
-
.sort(([a], [b]) => (a < b ? -1 : 1))
|
|
71
|
-
.map(([exp, local]) => (exp === local ? exp : `${exp} as ${local}`))
|
|
72
|
-
.join(', ');
|
|
73
|
-
pieces.push(`{ ${named} }`);
|
|
74
|
-
}
|
|
75
|
-
lines.push(`import ${pieces.join(', ')} from '${module}';`);
|
|
76
|
-
}
|
|
77
|
-
return lines.join('\n');
|
|
78
|
-
}
|
|
79
|
-
/** ImportNeeds for @mapples/sid-ast upsertImports, from a merged tree. */
|
|
80
|
-
export function importNeedsFor(root) {
|
|
81
|
-
const { uiNames, customs } = collectImportsTolerant(root);
|
|
82
|
-
const needs = [];
|
|
83
|
-
if (uiNames.length > 0)
|
|
84
|
-
needs.push({ module: UI_MODULE, named: uiNames });
|
|
85
|
-
for (const [local, origin] of customs) {
|
|
86
|
-
if (origin.module === '')
|
|
87
|
-
continue; // locally-defined component: nothing to import
|
|
88
|
-
needs.push(origin.exportName === 'default'
|
|
89
|
-
? { module: origin.module, defaultName: local }
|
|
90
|
-
: { module: origin.module, named: [origin.exportName] });
|
|
91
|
-
}
|
|
92
|
-
return needs;
|
|
93
|
-
}
|
|
94
|
-
/** Like collectImports but tolerant of local (#Name) customs — used for healing. */
|
|
95
|
-
function collectImportsTolerant(root) {
|
|
96
|
-
const uiNames = new Set();
|
|
97
|
-
const customs = new Map();
|
|
98
|
-
const walk = (node) => {
|
|
99
|
-
if (node.type === 'Custom') {
|
|
100
|
-
const name = node.props.name;
|
|
101
|
-
const importRef = node.props.importRef;
|
|
102
|
-
if (typeof name === 'string' && typeof importRef === 'string') {
|
|
103
|
-
const origin = parseImportRef(importRef);
|
|
104
|
-
if (!customs.has(name))
|
|
105
|
-
customs.set(name, origin);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
uiNames.add(node.type);
|
|
110
|
-
}
|
|
111
|
-
for (const child of node.children)
|
|
112
|
-
walk(child);
|
|
113
|
-
};
|
|
114
|
-
walk(root);
|
|
115
|
-
return { uiNames: [...uiNames].sort(), customs };
|
|
116
|
-
}
|
|
1
|
+
// The import block of a generated file — lives in @mapples/codegen (pure).
|
|
2
|
+
export { collectImports, importNeedsFor, parseImportRef, printImports, UI_MODULE, } from '@mapples/codegen';
|
|
117
3
|
//# sourceMappingURL=imports.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/codegen/imports.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"imports.js","sourceRoot":"","sources":["../../src/codegen/imports.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,EACL,cAAc,EACd,cAAc,EACd,cAAc,EACd,YAAY,EACZ,SAAS,GAEV,MAAM,kBAAkB,CAAC"}
|
|
@@ -1,16 +1,5 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type InstanceLinker } from '@mapples/codegen';
|
|
2
2
|
import type { ComponentEntity } from '../api/objects.js';
|
|
3
3
|
import type { ComponentsMap } from '../project/componentsMap.js';
|
|
4
|
-
|
|
5
|
-
export interface InstanceLinker {
|
|
6
|
-
/** File language -> canvas language, in place. Reports what could not link. */
|
|
7
|
-
link(dom: RenderDomNode, file: string, warn: (w: ExtractWarning) => void): void;
|
|
8
|
-
/** Canvas language -> file language, as a copy. Reports instances with no component. */
|
|
9
|
-
unlink(dom: RenderDomNode, file: string, warn: (w: ExtractWarning) => void): RenderDomNode;
|
|
10
|
-
/** Does this import, from this file, name a managed component? */
|
|
11
|
-
isLinked(origin: {
|
|
12
|
-
module: string;
|
|
13
|
-
exportName: string;
|
|
14
|
-
}, file: string): boolean;
|
|
15
|
-
}
|
|
4
|
+
export type { InstanceLinker } from '@mapples/codegen';
|
|
16
5
|
export declare function instanceLinker(componentsMap: ComponentsMap, components: Map<string, ComponentEntity>): InstanceLinker;
|
|
@@ -1,141 +1,30 @@
|
|
|
1
|
-
// Linked component instances
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// `<ProfileCard $sid="…" styled={{ … }} />` — which extraction reads as a
|
|
6
|
-
// `Custom` node with that import ref. On the CANVAS the same thing is a
|
|
7
|
-
// `ComponentInstance` node: `{ componentUuid, componentName, styled }`, the
|
|
8
|
-
// Creator's linked instance of the saved component. Base and remote trees
|
|
9
|
-
// always speak canvas; a tree read from a file speaks file. `link` and
|
|
10
|
-
// `unlink` convert, so the merge compares like with like and the file never
|
|
11
|
-
// sees a `ComponentInstance` tag (nothing exports one).
|
|
1
|
+
// Linked component instances (file language <-> canvas language) — the
|
|
2
|
+
// conversion lives in @mapples/codegen; this binds it to the CLI's
|
|
3
|
+
// components map and to `node:path`, so OS-native paths in the map resolve
|
|
4
|
+
// the way they always did.
|
|
12
5
|
import { dirname, posix, relative, sep } from 'node:path';
|
|
13
|
-
import {
|
|
14
|
-
import { parseImportRef } from './imports.js';
|
|
6
|
+
import { instanceLinker as linker, } from '@mapples/codegen';
|
|
15
7
|
const toPosix = (p) => p.split(sep).join(posix.sep);
|
|
16
|
-
/**
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
8
|
+
/** `node:path`-backed resolver over the project's OS paths. */
|
|
9
|
+
const nodeResolver = {
|
|
10
|
+
fileFor(fromFile, module) {
|
|
11
|
+
if (!module.startsWith('.'))
|
|
12
|
+
return null;
|
|
13
|
+
const resolved = posix.normalize(posix.join(toPosix(dirname(fromFile)), module));
|
|
14
|
+
return resolved.endsWith('.tsx') ? resolved : `${resolved}.tsx`;
|
|
15
|
+
},
|
|
16
|
+
moduleFor(fromFile, targetFile) {
|
|
17
|
+
let rel = toPosix(relative(dirname(fromFile), targetFile)).replace(/\.tsx$/, '');
|
|
18
|
+
if (!rel.startsWith('.'))
|
|
19
|
+
rel = `./${rel}`;
|
|
20
|
+
return rel;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
30
23
|
export function instanceLinker(componentsMap, components) {
|
|
31
|
-
const
|
|
32
|
-
const byUuid = new Map();
|
|
24
|
+
const posixMap = {};
|
|
33
25
|
for (const [id, mapping] of Object.entries(componentsMap)) {
|
|
34
|
-
|
|
35
|
-
const linked = {
|
|
36
|
-
id,
|
|
37
|
-
file: toPosix(mapping.file),
|
|
38
|
-
name: entity?.name ?? mapping.name,
|
|
39
|
-
uuid: entity?.uuid,
|
|
40
|
-
};
|
|
41
|
-
byFile.set(linked.file, linked);
|
|
42
|
-
if (linked.uuid)
|
|
43
|
-
byUuid.set(linked.uuid, linked);
|
|
26
|
+
posixMap[id] = { file: toPosix(mapping.file), name: mapping.name };
|
|
44
27
|
}
|
|
45
|
-
|
|
46
|
-
if (origin.exportName !== 'default')
|
|
47
|
-
return null;
|
|
48
|
-
const target = resolveModuleFile(file, origin.module);
|
|
49
|
-
return target ? (byFile.get(target) ?? null) : null;
|
|
50
|
-
};
|
|
51
|
-
return {
|
|
52
|
-
isLinked: (origin, file) => componentFor(origin, file) !== null,
|
|
53
|
-
link(dom, file, warn) {
|
|
54
|
-
const walk = (node) => {
|
|
55
|
-
node.children.forEach(walk);
|
|
56
|
-
if (node.type !== 'Custom')
|
|
57
|
-
return;
|
|
58
|
-
const { name, importRef, layout } = node.props;
|
|
59
|
-
if (typeof name !== 'string' || typeof importRef !== 'string')
|
|
60
|
-
return;
|
|
61
|
-
const component = componentFor(parseImportRef(importRef), file);
|
|
62
|
-
if (!component)
|
|
63
|
-
return;
|
|
64
|
-
if (!component.uuid) {
|
|
65
|
-
warn({
|
|
66
|
-
kind: 'UNKNOWN_ELEMENT_WITH_SID',
|
|
67
|
-
sid: node.sid,
|
|
68
|
-
detail: `<${name}> is the Creator component “${component.name}”, but that component has no uuid yet — pushed as a Custom placeholder; run \`mapples sync\` again after the component reaches the Creator`,
|
|
69
|
-
});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
const attrs = (layout ?? {});
|
|
73
|
-
const { styled, ...rest } = attrs;
|
|
74
|
-
for (const key of Object.keys(rest)) {
|
|
75
|
-
warn({
|
|
76
|
-
kind: 'NON_LITERAL_PROP',
|
|
77
|
-
sid: node.sid,
|
|
78
|
-
prop: key,
|
|
79
|
-
detail: `prop \`${key}\` on <${name}> stays in code only — a Creator component instance takes no props besides \`styled\``,
|
|
80
|
-
});
|
|
81
|
-
}
|
|
82
|
-
if (node.children.length > 0) {
|
|
83
|
-
warn({
|
|
84
|
-
kind: 'NON_LITERAL_PROP',
|
|
85
|
-
sid: node.sid,
|
|
86
|
-
prop: 'children',
|
|
87
|
-
detail: `children of <${name}> are not part of the Creator instance — kept in code only`,
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
node.type = 'ComponentInstance';
|
|
91
|
-
node.props = {
|
|
92
|
-
componentUuid: component.uuid,
|
|
93
|
-
componentName: component.name,
|
|
94
|
-
...(styled !== undefined ? { styled } : {}),
|
|
95
|
-
};
|
|
96
|
-
node.children = [];
|
|
97
|
-
};
|
|
98
|
-
walk(dom);
|
|
99
|
-
},
|
|
100
|
-
unlink(dom, file, warn) {
|
|
101
|
-
// A component the Creator named after its root ("View", "Button"…)
|
|
102
|
-
// cannot share a local name with the primitive the file imports.
|
|
103
|
-
const primitiveTypes = new Set();
|
|
104
|
-
const collectTypes = (node) => {
|
|
105
|
-
if (node.type !== 'Custom' && node.type !== 'ComponentInstance') {
|
|
106
|
-
primitiveTypes.add(node.type);
|
|
107
|
-
}
|
|
108
|
-
node.children.forEach(collectTypes);
|
|
109
|
-
};
|
|
110
|
-
collectTypes(dom);
|
|
111
|
-
const localName = (component) => pageComponentName(component.name, primitiveTypes, 'Component');
|
|
112
|
-
const convert = (node) => {
|
|
113
|
-
const children = node.children.map(convert);
|
|
114
|
-
if (node.type !== 'ComponentInstance')
|
|
115
|
-
return { ...node, children };
|
|
116
|
-
const { componentUuid, componentName, styled } = node.props;
|
|
117
|
-
const component = typeof componentUuid === 'string' ? byUuid.get(componentUuid) : undefined;
|
|
118
|
-
if (!component) {
|
|
119
|
-
warn({
|
|
120
|
-
kind: 'UNKNOWN_ELEMENT_WITH_SID',
|
|
121
|
-
sid: node.sid,
|
|
122
|
-
detail: `instance of component “${String(componentName ?? componentUuid)}” has no component file to import — left as a ComponentInstance tag`,
|
|
123
|
-
});
|
|
124
|
-
return { ...node, children };
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
...node,
|
|
128
|
-
type: 'Custom',
|
|
129
|
-
props: {
|
|
130
|
-
name: localName(component),
|
|
131
|
-
importRef: `${moduleForFile(file, component.file)}#default`,
|
|
132
|
-
layout: styled !== undefined ? { styled } : {},
|
|
133
|
-
},
|
|
134
|
-
children,
|
|
135
|
-
};
|
|
136
|
-
};
|
|
137
|
-
return convert(dom);
|
|
138
|
-
},
|
|
139
|
-
};
|
|
28
|
+
return linker(posixMap, components, nodeResolver);
|
|
140
29
|
}
|
|
141
30
|
//# sourceMappingURL=instances.js.map
|