@tinkerlandai/indiana-iam 0.4.0 → 0.5.0
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 +27 -4
- package/assets/viewer.js +60 -32
- package/package.json +8 -2
- package/src/analyze.mjs +199 -67
- package/src/anchors.mjs +2 -0
- package/src/build-styles.mjs +14 -9
- package/src/component-registry.mjs +1 -1
- package/src/document-material.mjs +180 -0
- package/src/dom-payload-json.mjs +2 -2
- package/src/dom-payload.mjs +3 -3
- package/src/framework-routes.mjs +1 -2
- package/src/generate.mjs +104 -24
- package/src/index.d.ts +0 -1
- package/src/index.mjs +1 -1
- package/src/json.mjs +2 -3
- package/src/library-entry.mjs +5 -2
- package/src/node-hashes.mjs +1 -1
- package/src/render-index.mjs +7 -7
- package/src/route-composition.mjs +5 -5
- package/src/route-tree.mjs +9 -9
- package/src/routing.mjs +7 -6
- package/src/schema-definition.mjs +13 -15
- package/src/selected-manifest.mjs +12 -0
- package/src/source-aliases.mjs +34 -0
- package/src/source-charts.mjs +15 -0
- package/src/source-css-modules.mjs +79 -0
- package/src/source-files.mjs +8 -7
- package/src/source-flowbite.mjs +60 -0
- package/src/source-i18next.mjs +22 -0
- package/src/source-mantine.mjs +61 -0
- package/src/source-mdx.mjs +92 -0
- package/src/source-media.mjs +12 -3
- package/src/source-styles.mjs +9 -0
- package/src/static-query.mjs +67 -7
- package/src/svg-preview.mjs +23 -0
- package/src/tanstack-routes.mjs +1 -1
- package/src/ui-structure.mjs +7 -18
- package/src/viewer-index.mjs +49 -0
package/src/analyze.mjs
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import {referencedRasterSources} from "./source-media.mjs";
|
|
3
|
+
import {sourceAliases} from './source-aliases.mjs';
|
|
4
|
+
import {sourceCssModules} from './source-css-modules.mjs';
|
|
5
|
+
import {mantinePrimitive} from './source-mantine.mjs';
|
|
6
|
+
import {sourceMdx} from './source-mdx.mjs';
|
|
7
|
+
import {attachSourceStyles} from './source-styles.mjs';
|
|
8
|
+
import {sourceI18next} from './source-i18next.mjs';
|
|
3
9
|
import {uiEnvironmentPrimitive} from "./source-environment.mjs";
|
|
4
10
|
import {sourceChart} from "./source-charts.mjs";
|
|
11
|
+
import {flowbiteShape,rootFlowbiteTheme} from "./source-flowbite.mjs";
|
|
5
12
|
import path from "node:path";
|
|
6
13
|
import { automaticSourceAnchors, anchorAttributes, sourceScriptKind } from "./anchors.mjs";
|
|
7
14
|
import { sourceFiles } from "./source-files.mjs";
|
|
@@ -41,6 +48,7 @@ import { sensitiveName, redactLiteral, privateUrl } from "./privacy.mjs";
|
|
|
41
48
|
const isUnknown = (value) => value === UNKNOWN;
|
|
42
49
|
const COMPONENT=Symbol('source-component');
|
|
43
50
|
const TRANSLATION=Symbol('source-translation-catalog');
|
|
51
|
+
const TRANSLATION_FORMAT=Symbol('source-translation-format');
|
|
44
52
|
const UI_SETTER=Symbol('source-ui-setter');
|
|
45
53
|
const UI_PRIMITIVE=Symbol('source-ui-primitive');
|
|
46
54
|
|
|
@@ -83,11 +91,11 @@ function staticStyle(value, unsupported) {
|
|
|
83
91
|
}).join(";");
|
|
84
92
|
}
|
|
85
93
|
const allowedTags = new Set(
|
|
86
|
-
"main section article aside header footer nav div span p h1 h2 h3 h4 h5 h6 a button form label input select option textarea ul ol li dl dt dd table thead tbody tr th td caption fieldset legend details summary pre code blockquote strong em b i small s u mark time br hr img picture source svg path circle rect line polyline polygon ellipse g title".split(
|
|
94
|
+
"main section article aside header footer nav div span p h1 h2 h3 h4 h5 h6 a button form label input select option textarea ul ol li dl dt dd table thead tbody tfoot tr th td caption fieldset legend details summary pre code blockquote strong em b i small s del u mark time br hr wbr img picture source svg path circle rect line polyline polygon ellipse g title".split(
|
|
87
95
|
" ",
|
|
88
96
|
),
|
|
89
97
|
);
|
|
90
|
-
const voidTags = new Set(["input", "br", "hr", "img", "source"]);
|
|
98
|
+
const voidTags = new Set(["input", "br", "hr", "wbr", "img", "source"]);
|
|
91
99
|
const escape = (text) =>
|
|
92
100
|
redactLiteral(text).replace(
|
|
93
101
|
/[&<>"']/g,
|
|
@@ -187,8 +195,8 @@ export async function analyze({
|
|
|
187
195
|
name,
|
|
188
196
|
repository = "",
|
|
189
197
|
commit = "",
|
|
190
|
-
maxFiles =
|
|
191
|
-
maxBytes =
|
|
198
|
+
maxFiles = Infinity,
|
|
199
|
+
maxBytes = Infinity,
|
|
192
200
|
navigationPaths = [],
|
|
193
201
|
entry,
|
|
194
202
|
automaticAnchors = false,
|
|
@@ -201,7 +209,7 @@ export async function analyze({
|
|
|
201
209
|
elements = new Map(),
|
|
202
210
|
components = new Map(),
|
|
203
211
|
assets = new Map();
|
|
204
|
-
const cssSources = [];
|
|
212
|
+
const cssSources = [], cssModuleFiles = new Map();
|
|
205
213
|
const jsonResources=new Map(),translationResources=new Set();
|
|
206
214
|
const presentation={conditions:[],tabs:[],navigation:[],regions:[],collections:[],fragments:[],attributes:[],attributeSets:[]},collectionTemplates=new Map();
|
|
207
215
|
const ui = { variables: [], bindings: [], transitions: [], uncovered: [] };
|
|
@@ -210,7 +218,6 @@ export async function analyze({
|
|
|
210
218
|
function gap(code, file, detail) {
|
|
211
219
|
detail = redactLiteral(detail);
|
|
212
220
|
if (
|
|
213
|
-
gaps.length < 1000 &&
|
|
214
221
|
!gaps.some(
|
|
215
222
|
(x) => x.code === code && x.file === file && x.detail === detail,
|
|
216
223
|
)
|
|
@@ -224,10 +231,11 @@ export async function analyze({
|
|
|
224
231
|
const real = await fs.realpath(absolute);
|
|
225
232
|
if (!real.startsWith(root + path.sep))
|
|
226
233
|
throw new Error("Source path escapes root");
|
|
227
|
-
if (
|
|
234
|
+
if ((byteCount += stat.size) > maxBytes)
|
|
228
235
|
throw new Error("Source byte budget exceeded");
|
|
229
236
|
const bytes = await fs.readFile(absolute);
|
|
230
|
-
const
|
|
237
|
+
const originalText = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
238
|
+
let text = originalText;
|
|
231
239
|
inventory.push({
|
|
232
240
|
file,
|
|
233
241
|
sha256: sha256(bytes),
|
|
@@ -235,33 +243,32 @@ export async function analyze({
|
|
|
235
243
|
});
|
|
236
244
|
if(file.endsWith('.json')){try{jsonResources.set(file,JSON.parse(text));}catch{/* Non-resource JSON stays opaque. */}continue;}
|
|
237
245
|
if (file.endsWith(".css")) {
|
|
246
|
+
if (file.endsWith('.module.css')) { cssModuleFiles.set(file, text); continue; }
|
|
238
247
|
gap(
|
|
239
|
-
|
|
240
|
-
? "CSS_MODULES_UNSUPPORTED"
|
|
241
|
-
: "STYLE_SOURCE_PARTIAL",
|
|
248
|
+
"STYLE_SOURCE_PARTIAL",
|
|
242
249
|
file,
|
|
243
250
|
"Only root/dark tokens and pinned utility rules are reconstructed; scoped/custom selectors, keyframes and original font rules are not compiled",
|
|
244
251
|
);
|
|
245
252
|
if (!file.endsWith(".module.css")) cssSources.push({ file, text });
|
|
246
253
|
continue;
|
|
247
254
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
continue;
|
|
252
|
-
}
|
|
255
|
+
const mdx = /\.mdx?$/.test(file) ? sourceMdx(file, originalText, gap) : null;
|
|
256
|
+
if (mdx) text = mdx.text;
|
|
257
|
+
if (!mdx && !/\.[cm]?[jt]sx?$/.test(file)) continue;
|
|
253
258
|
const source = ts.createSourceFile(
|
|
254
259
|
file,
|
|
255
260
|
text,
|
|
256
261
|
ts.ScriptTarget.Latest,
|
|
257
262
|
true,
|
|
258
|
-
sourceScriptKind(file, ts),
|
|
263
|
+
mdx ? ts.ScriptKind.TSX : sourceScriptKind(file, ts),
|
|
259
264
|
);
|
|
260
265
|
const module = {
|
|
261
266
|
file,
|
|
262
267
|
text,
|
|
263
268
|
source,
|
|
264
|
-
anchors: automaticAnchors ? automaticSourceAnchors(file, source) : new Map(),
|
|
269
|
+
anchors: automaticAnchors && !mdx ? automaticSourceAnchors(file, source) : new Map(),
|
|
270
|
+
mdx,
|
|
271
|
+
originalSource: mdx ? ts.createSourceFile(file, originalText, ts.ScriptTarget.Latest, false) : source,
|
|
265
272
|
bindings: new Map(),
|
|
266
273
|
imports: new Map(),
|
|
267
274
|
exports: new Map(),
|
|
@@ -333,14 +340,8 @@ export async function analyze({
|
|
|
333
340
|
}
|
|
334
341
|
modules.set(file, module);
|
|
335
342
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const config = ts.parseConfigFileTextToJson(
|
|
339
|
-
"tsconfig.json",
|
|
340
|
-
await fs.readFile(path.join(root, "tsconfig.json"), "utf8"),
|
|
341
|
-
).config;
|
|
342
|
-
alias = config.compilerOptions?.paths || alias;
|
|
343
|
-
} catch { /* Source projects may omit tsconfig.json. */ }
|
|
343
|
+
const alias = await sourceAliases(root,ts);
|
|
344
|
+
const cssModules = sourceCssModules({files: cssModuleFiles, aliases: alias, gap, redact: redactLiteral});
|
|
344
345
|
function resolveModule(from, specifier) {
|
|
345
346
|
let relative;
|
|
346
347
|
if (specifier.startsWith("."))
|
|
@@ -367,6 +368,8 @@ export async function analyze({
|
|
|
367
368
|
".jsx",
|
|
368
369
|
".js",
|
|
369
370
|
".mjs",
|
|
371
|
+
".mdx",
|
|
372
|
+
".md",
|
|
370
373
|
"/index.tsx",
|
|
371
374
|
"/index.ts",
|
|
372
375
|
"/index.jsx",
|
|
@@ -388,6 +391,7 @@ export async function analyze({
|
|
|
388
391
|
}
|
|
389
392
|
function sourceContextCall(node,module,ctx){
|
|
390
393
|
const imported=externalImport(module,node.expression.getText(module.source));
|
|
394
|
+
if(imported?.specifier==='react-i18next'&&imported.name==='useTranslation')return {t:translationHook(node,module,ctx)};
|
|
391
395
|
if(imported?.specifier==='react'&&imported.name==='useContext'&&ts.isIdentifier(node.arguments[0]))return ctx.__iamContexts?.get(contextKey(module,node.arguments[0].text))??UNKNOWN;
|
|
392
396
|
const ref=ts.isIdentifier(node.expression)&&binding(module,node.expression.text),fn=ref&&functionFrom(ref.node);
|
|
393
397
|
if(!fn?.body||!ts.isBlock(fn.body))return UNKNOWN;
|
|
@@ -399,14 +403,39 @@ export async function analyze({
|
|
|
399
403
|
if(primitive?.specifier==='react-i18next'&&primitive.name==='useTranslation'&&ts.isObjectBindingPattern(decl.name)&&decl.name.elements.some(e=>(e.propertyName?.text||e.name.text)==='t'&&e.name.text===result.text)){
|
|
400
404
|
const catalogs=[...ref.module.imports.values()].filter(i=>i.specifier.endsWith('.json')).map(i=>jsonResource(ref.module.file,i.specifier)).filter(Boolean);
|
|
401
405
|
if(catalogs.length===1){translationResources.add(catalogs[0]);return {[TRANSLATION]:catalogs[0]};}
|
|
406
|
+
const locals={...ctx};fn.parameters.forEach((p,i)=>{if(ts.isIdentifier(p.name))locals[p.name.text]=evalExpression(node.arguments[i],module,ctx);});
|
|
407
|
+
return translationHook(call,ref.module,locals);
|
|
402
408
|
}
|
|
403
409
|
}
|
|
404
410
|
return UNKNOWN;
|
|
405
411
|
}
|
|
412
|
+
let i18nextPreview;
|
|
413
|
+
function translationHook(node,module,ctx){
|
|
414
|
+
i18nextPreview??=sourceI18next({ts,modules,binding,imported:externalImport,jsonResource})??false;
|
|
415
|
+
if(!i18nextPreview)return UNKNOWN;
|
|
416
|
+
const namespace=node.arguments[0]?evalExpression(node.arguments[0],module,ctx):i18nextPreview.namespace;
|
|
417
|
+
const options=node.arguments[1]?evalExpression(node.arguments[1],module,ctx):{};
|
|
418
|
+
if(typeof namespace!=='string'||isUnknown(options)||options?.keyPrefix!==undefined&&typeof options.keyPrefix!=='string')return UNKNOWN;
|
|
419
|
+
let catalog=i18nextPreview.resources[i18nextPreview.language]?.[namespace];
|
|
420
|
+
if(typeof options?.keyPrefix==='string')catalog=options.keyPrefix.split('.').reduce((v,k)=>v&&Object.hasOwn(v,k)?v[k]:undefined,catalog);
|
|
421
|
+
if(!catalog||typeof catalog!=='object')return UNKNOWN;
|
|
422
|
+
gap('UI_LOCALE_FALLBACK_PREVIEW',i18nextPreview.file,'Read-only preview uses the source fallback locale '+i18nextPreview.language+'; browser language, storage and runtime locale selection are not observed.');
|
|
423
|
+
translationResources.add(catalog);return {[TRANSLATION]:catalog,[TRANSLATION_FORMAT]:{prefix:i18nextPreview.prefix,suffix:i18nextPreview.suffix}};
|
|
424
|
+
}
|
|
406
425
|
function basePrimitive(module,tag,seen=new Set()){
|
|
407
426
|
if(seen.has(module.file+'#'+tag)||seen.size>8)return null;seen.add(module.file+'#'+tag);
|
|
408
427
|
const [name,part,extra]=tag.split('.'),ref=module.imports.get(name);
|
|
409
428
|
const imported=externalImport(module,tag);
|
|
429
|
+
if (ref?.specifier === '@mantine/core' && ref.name === 'Tabs' && !extra) return {family:'Tabs',part:part ?? 'Root',mantine:true};
|
|
430
|
+
if(imported?.specifier==='@headlessui/react'){
|
|
431
|
+
const part={Dialog:'Root',DialogPanel:'Popup',DialogBackdrop:'Backdrop',DialogTitle:'Title',Description:'Description'}[imported.name];
|
|
432
|
+
if(part)return {family:'Dialog',part,rootVisibility:part==='Root'};
|
|
433
|
+
}
|
|
434
|
+
if(imported?.specifier==='react-aria-components'){
|
|
435
|
+
const part={DialogTrigger:'Root',MenuTrigger:'Root',TooltipTrigger:'Root',ModalOverlay:'Backdrop',Modal:'Popup',Popover:'Popup',Dialog:'Popup',Menu:'Content',MenuItem:'Item',Button:'Trigger',Heading:'Title'}[imported.name];
|
|
436
|
+
if(part)return {family:'AriaDialog',part,...(imported.name==='Menu'?{role:'menu'}:['Modal','Popover'].includes(imported.name)?{role:null}:{})};
|
|
437
|
+
}
|
|
438
|
+
if(ref?.specifier==='cmdk'&&ref.name==='Command'&&part==='Dialog'&&!extra)return {family:'Dialog',part:'Root',rootVisibility:true};
|
|
410
439
|
const radixFamilies={'dialog':'Dialog','alert-dialog':'AlertDialog','popover':'Popover','dropdown-menu':'Menu','context-menu':'Menu','tooltip':'Tooltip','hover-card':'Popover','tabs':'Tabs','collapsible':'Collapsible'};
|
|
411
440
|
const radix=imported?.specifier?.match(/^@radix-ui\/react-([a-z-]+)$/)?.[1];
|
|
412
441
|
if(radixFamilies[radix]) {
|
|
@@ -532,8 +561,9 @@ export async function analyze({
|
|
|
532
561
|
return target;
|
|
533
562
|
}
|
|
534
563
|
function sourceLocation(module, node, symbol) {
|
|
535
|
-
const
|
|
536
|
-
|
|
564
|
+
const generated = node.getStart(module.source);
|
|
565
|
+
const loc = module.originalSource.getLineAndCharacterOfPosition(
|
|
566
|
+
module.mdx ? module.mdx.position(generated) : generated,
|
|
537
567
|
);
|
|
538
568
|
return {
|
|
539
569
|
file: module.file,
|
|
@@ -544,16 +574,21 @@ export async function analyze({
|
|
|
544
574
|
};
|
|
545
575
|
}
|
|
546
576
|
function sourceComponent(node,module){
|
|
577
|
+
const tabler=ts.isIdentifier(node)&&externalImport(module,node.text);
|
|
578
|
+
if(tabler?.specifier==='@tabler/icons-react'&&/^Icon[A-Z]/.test(tabler.name)){
|
|
579
|
+
const icon=lucideSource(tabler.name.slice(4));
|
|
580
|
+
if(icon){gap('ICON_SOURCE_APPROXIMATION',module.file,tabler.name+': inert Lucide counterpart used for source preview; original Tabler geometry is not claimed.');return icon;}
|
|
581
|
+
}
|
|
547
582
|
const imported=ts.isIdentifier(node)&&externalImport(module,node.text);if(imported?.specifier==='@radix-ui/react-slot'&&['Slot','Root'].includes(imported.name))return {[UI_PRIMITIVE]:imported};if(imported?.specifier==='lucide-react'){const icon=lucideSource(imported.name);if(icon)return icon;}
|
|
548
583
|
const ref=ts.isIdentifier(node)?binding(module,node.text):null;const def=componentsByFunction.get(node)??(ref&&componentDefs.get(ref.module.file+'#'+ref.name));
|
|
549
584
|
return def?{[COMPONENT]:def}:null;
|
|
550
585
|
}
|
|
551
|
-
function environment(node,module,
|
|
586
|
+
function environment(node,module,_context){
|
|
552
587
|
const value=uiEnvironmentPrimitive({ts,node,module,binding,imported:externalImport,evaluate:evalExpression});
|
|
553
588
|
if(value?.kind==='empty-preference'){gap('UI_PREFERENCE_EMPTY_PREVIEW',module.file,'Source-declared SSR fallback for a UI preference; preview starts without cookies, never reads merchant browser state.');return [undefined];}
|
|
554
589
|
return value;
|
|
555
590
|
}
|
|
556
|
-
function query(node,module,context){return staticQuery({ts,node,module,context,binding,unknown:UNKNOWN,redact:redactLiteral,sensitive:sensitiveName,reference:sourceComponent,isReference:v=>Boolean(v?.[COMPONENT]||v?.[LUCIDE_SOURCE]||v?.[UI_PRIMITIVE]),imported:externalImport,project:(n,m,c)=>{const v=environment(n,m,c);return Array.isArray(v)?v:null;}});}
|
|
591
|
+
function query(node,module,context,allowAsyncSource=false){return staticQuery({ts,node,module,context,binding,unknown:UNKNOWN,redact:redactLiteral,sensitive:sensitiveName,reference:sourceComponent,isReference:v=>Boolean(v?.[COMPONENT]||v?.[LUCIDE_SOURCE]||v?.[UI_PRIMITIVE]),imported:externalImport,allowAsyncSource,onAsyncSource:({timerSkipped})=>gap('ASYNC_SOURCE_RETURN_PREVIEW',module.file,'Only source-declared literal data is projected; network, actions, loading/error outcomes and query callbacks are not executed.'+(timerSkipped?' A source-proven timer-only delay is skipped without invoking timers.':'')),project:(n,m,c)=>{if(ts.isIdentifier(n.expression)&&c[n.expression.text]?.[TRANSLATION]){const value=evalExpression(n,m,c);return isUnknown(value)?null:[value];}const v=environment(n,m,c);return Array.isArray(v)?v:null;}});}
|
|
557
592
|
function evalExpression(
|
|
558
593
|
node,
|
|
559
594
|
module,
|
|
@@ -564,6 +599,7 @@ export async function analyze({
|
|
|
564
599
|
node = unwrap(node);
|
|
565
600
|
if (!node || depth > 30) return UNKNOWN;
|
|
566
601
|
const ev = (n) => evalExpression(n, module, context, stack, depth + 1);
|
|
602
|
+
if (ts.isAwaitExpression(node)) return query(node, module, context, true);
|
|
567
603
|
const component=!(ts.isIdentifier(node)&&Object.hasOwn(context,node.text))&&sourceComponent(node,module);if(component)return component;
|
|
568
604
|
if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node))
|
|
569
605
|
return ts.isNumericLiteral(node) ? Number(node.text) : redactLiteral(node.text);
|
|
@@ -572,12 +608,16 @@ export async function analyze({
|
|
|
572
608
|
if (node.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
573
609
|
if (ts.isIdentifier(node)) {
|
|
574
610
|
if (Object.hasOwn(context, node.text)) return context[node.text];
|
|
611
|
+
const cssModule = cssModules.resolve(module, module.imports.get(node.text));
|
|
612
|
+
if (cssModule) return cssModule;
|
|
575
613
|
const variableKey=context.__iamVariableKeys?.[context.__iamSetters?.[node.text]];
|
|
576
614
|
if(variableKey)return {[UI_SETTER]:{variableKey,value:{op:'event',key:'value'},payload:{value:ui.variables.find(v=>v.variableKey===variableKey)?.valueType}}};
|
|
577
615
|
if (node.text === "undefined") return undefined;
|
|
578
616
|
const image=module.imports.get(node.text);
|
|
579
|
-
if(image?.name==='default'
|
|
580
|
-
|
|
617
|
+
if(image?.name==='default'&&/^[^?#]+\.(?:png|jpe?g|webp|gif|svg)$/i.test(image.specifier)){
|
|
618
|
+
let file=image.specifier.startsWith('.')?path.posix.normalize(path.posix.join(path.posix.dirname(module.file),image.specifier)):null;
|
|
619
|
+
if(!file)for(const[pattern,targets]of Object.entries(alias)){const parts=pattern.split('*');if(parts.length===2&&image.specifier.startsWith(parts[0])&&image.specifier.endsWith(parts[1])&&Array.isArray(targets)&&targets.length===1&&typeof targets[0]==='string'){const value=image.specifier.slice(parts[0].length,image.specifier.length-parts[1].length||undefined);file=path.posix.normalize(targets[0].replace('*',value));break;}}
|
|
620
|
+
if(!file)return UNKNOWN;
|
|
581
621
|
if(!file.startsWith('../')&&!file.split('/').some(p=>p.startsWith('.'))&&!sensitiveName(file))return '/__iam_source__/'+file;
|
|
582
622
|
}
|
|
583
623
|
const token = module.file + "#" + node.text;
|
|
@@ -690,7 +730,13 @@ export async function analyze({
|
|
|
690
730
|
const primitive=externalImport(module,callee);
|
|
691
731
|
if(['react-router','react-router-dom'].includes(primitive?.specifier)&&primitive.name==='useLocation'&&typeof context.__iamRoutePath==='string')return {pathname:context.__iamRoutePath,search:UNKNOWN,hash:UNKNOWN};
|
|
692
732
|
const translation=ts.isIdentifier(node.expression)&&context[node.expression.text]?.[TRANSLATION];
|
|
693
|
-
if(translation){
|
|
733
|
+
if(translation){
|
|
734
|
+
const key=ev(node.arguments[0]);if(typeof key!=='string')return UNKNOWN;const value=key.split('.').reduce((value,key)=>value&&Object.hasOwn(Object(value),key)?value[key]:undefined,translation);if(typeof value!=='string')return UNKNOWN;
|
|
735
|
+
const format=context[node.expression.text][TRANSLATION_FORMAT]??{prefix:'{{',suffix:'}}'},options=node.arguments[1]?ev(node.arguments[1]):{};
|
|
736
|
+
const pattern=format.prefix==='{{'&&format.suffix==='}}'?/\{\{([A-Za-z_][A-Za-z0-9_]*)\}\}/g:format.prefix==='{'&&format.suffix==='}'?/\{([A-Za-z_][A-Za-z0-9_]*)\}/g:null;if(!pattern)return UNKNOWN;
|
|
737
|
+
let missing=false;const text=value.replace(pattern,(_,k)=>{const v=options&&Object.hasOwn(Object(options),k)?options[k]:UNKNOWN;if(typeof v==='string'||typeof v==='number'&&Number.isFinite(v))return String(v);missing=true;return '';});
|
|
738
|
+
return !missing&&!/[{}]/.test(text)&&text.length<=4000?redactLiteral(text):UNKNOWN;
|
|
739
|
+
}
|
|
694
740
|
if(primitive?.specifier==='react'&&primitive.name==='useMemo'&&node.arguments.length===2){
|
|
695
741
|
const fn=node.arguments[0];if(ts.isArrowFunction(fn)&&!fn.modifiers?.length&&!fn.parameters.length&&!ts.isBlock(fn.body))return ev(fn.body);
|
|
696
742
|
}
|
|
@@ -806,7 +852,7 @@ export async function analyze({
|
|
|
806
852
|
}
|
|
807
853
|
const forwarded = new WeakMap(), objectBindings = new WeakMap();
|
|
808
854
|
function componentContext(def, props) {
|
|
809
|
-
const ctx = { ...props, __iamSetters: {}, __iamStates: new Set(), __iamStateNodes: {}, __iamLocals: new Map(), __iamPropBindings: new Map(), __iamPropHandlers: new Map() };
|
|
855
|
+
const ctx = { ...props, __iamSetters: {}, __iamStates: new Set(), __iamStateNodes: {}, __iamLocals: new Map(), __iamQueryLocals: new Map(), __iamPropBindings: new Map(), __iamPropHandlers: new Map(), __iamDisclosures: [] };
|
|
810
856
|
const param = def.fn?.parameters?.[0];
|
|
811
857
|
if (param) {
|
|
812
858
|
if (ts.isIdentifier(param.name)) ctx[param.name.text] = props;
|
|
@@ -830,6 +876,7 @@ export async function analyze({
|
|
|
830
876
|
if (handler) ctx.__iamPropHandlers.set(el.name.getText(), handler);
|
|
831
877
|
}
|
|
832
878
|
}
|
|
879
|
+
if (def.fn?.body&&ts.isBlock(def.fn.body)) for (const statement of def.fn.body.statements) if (ts.isFunctionDeclaration(statement) && statement.name) ctx.__iamLocals.set(statement.name.text, statement);
|
|
833
880
|
if (def.fn?.body&&ts.isBlock(def.fn.body))
|
|
834
881
|
for (const s of def.fn.body.statements)
|
|
835
882
|
if (ts.isVariableStatement(s))
|
|
@@ -846,6 +893,7 @@ export async function analyze({
|
|
|
846
893
|
for(const field of d.name.elements)if(ts.isIdentifier(field.name)&&!field.dotDotDotToken){
|
|
847
894
|
const key=field.propertyName?.text||field.name.text;
|
|
848
895
|
ctx[field.name.text]=!isUnknown(value)&&value&&typeof value==='object'&&Object.hasOwn(value,key)?value[key]:field.initializer?evalExpression(field.initializer,def.module,ctx):UNKNOWN;
|
|
896
|
+
ctx.__iamQueryLocals.set(field.name.text,d.initializer);
|
|
849
897
|
const inherited=value&&typeof value==='object'&&objectBindings.get(value)?.get(key);
|
|
850
898
|
if(inherited)ctx.__iamPropBindings.set(field.name.text,inherited);
|
|
851
899
|
const setter=value?.[key]?.[UI_SETTER];
|
|
@@ -853,6 +901,18 @@ export async function analyze({
|
|
|
853
901
|
}
|
|
854
902
|
} else if (ts.isArrayBindingPattern(d.name)) {
|
|
855
903
|
const call = unwrap(d.initializer), hook = call && ts.isCallExpression(call) && ts.isIdentifier(call.expression) && def.module.imports.get(call.expression.text);
|
|
904
|
+
if (hook?.specifier === '@mantine/hooks' && hook.name === 'useDisclosure') {
|
|
905
|
+
const state = d.name.elements[0], handlers = d.name.elements[1]?.name;
|
|
906
|
+
if (call.arguments.length > 1 || !state || !ts.isIdentifier(state.name) || state.dotDotDotToken) {gap('DISCLOSURE_HOOK_UNOBSERVED',def.module.file,'Only a source boolean useDisclosure without lifecycle callbacks is simulated.');continue;}
|
|
907
|
+
const label = state.name.text;
|
|
908
|
+
ctx[label] = call.arguments.length ? evalExpression(call.arguments[0], def.module, ctx) : false;
|
|
909
|
+
ctx.__iamStates.add(label); ctx.__iamStateNodes[label] = d;
|
|
910
|
+
if (handlers && ts.isObjectBindingPattern(handlers)) {
|
|
911
|
+
for (const h of handlers.elements) if (!h.dotDotDotToken && ts.isIdentifier(h.name) && ['open','close','toggle'].includes(h.propertyName?.text ?? h.name.text)) ctx.__iamDisclosures.push({label,name:h.name.text,op:h.propertyName?.text ?? h.name.text});
|
|
912
|
+
} else if (handlers && ts.isIdentifier(handlers)) for (const op of ['open','close','toggle']) ctx.__iamDisclosures.push({label,name:handlers.text+'.'+op,op});
|
|
913
|
+
gap('DISCLOSURE_SOURCE_PREVIEW',def.module.file,'Local boolean disclosure state only; hook callbacks and browser effects are not executed.');
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
856
916
|
if (hook?.specifier === "react" && hook.name === "useActionState") {
|
|
857
917
|
const key = d.name.elements[0]?.name?.text, pending = d.name.elements[2]?.name?.text, initial = evalExpression(call.arguments[1], def.module, ctx);
|
|
858
918
|
if (key && !sensitiveName(key) && initial && !isUnknown(initial) && typeof initial === "object" && !Array.isArray(initial)) {
|
|
@@ -941,6 +1001,7 @@ export async function analyze({
|
|
|
941
1001
|
)
|
|
942
1002
|
throw new Error("Invalid source basePath");
|
|
943
1003
|
const selection = await sourceEntry({ root, modules, resolveModule, ts, entry });
|
|
1004
|
+
const flowbiteTheme=rootFlowbiteTheme({ts,modules:selection.discoveryModules,imported:externalImport,evaluate:evalExpression});
|
|
944
1005
|
if (selection.htmlSource) inventory.push(selection.htmlSource);
|
|
945
1006
|
inventory.sort((a, b) => a.file < b.file ? -1 : a.file > b.file ? 1 : 0);
|
|
946
1007
|
const compositions = frameworkRoutes({ modules, ...selection, resolveModule, ts, sourceLocation, navigationPaths, gap, resolution, inlineComponent });
|
|
@@ -999,7 +1060,6 @@ export async function analyze({
|
|
|
999
1060
|
const record = new Map(),
|
|
1000
1061
|
used = new Set(),
|
|
1001
1062
|
branches = [],attributeRequests=[];
|
|
1002
|
-
let renderedCount = 0;
|
|
1003
1063
|
function renderComponent(def, props, instance, depth) {
|
|
1004
1064
|
if (depth === 0 && composition.entryMode === "soft") instance = composition.compositionKey + ":" + instance;
|
|
1005
1065
|
// Component recursion and JSX nesting are separate budgets. Counting DOM
|
|
@@ -1011,7 +1071,7 @@ export async function analyze({
|
|
|
1011
1071
|
used.add(def.key + ":" + instance);
|
|
1012
1072
|
if (!page.componentKeys.includes(def.key))
|
|
1013
1073
|
page.componentKeys.push(def.key);
|
|
1014
|
-
props.__iamRoutePath=/[
|
|
1074
|
+
props.__iamRoutePath=/[[\]]/.test(route)?UNKNOWN:route;
|
|
1015
1075
|
const ctx = componentContext(def, props);
|
|
1016
1076
|
ctx.__iamOutlet = props.__iamOutlet;
|
|
1017
1077
|
ctx.__iamScope = identity("state-scope", {
|
|
@@ -1039,6 +1099,10 @@ export async function analyze({
|
|
|
1039
1099
|
ui.variables.push({ variableKey, routeKey: pageKey, scopeKey: ctx.__iamScope, label:ctx.__iamViewportQueries?.[label]?'@media '+ctx.__iamViewportQueries[label]:label, valueType: typeof initialValue, initialValue, source: sourceLocation(def.module, ctx.__iamStateNodes[label], def.symbol) });
|
|
1040
1100
|
}
|
|
1041
1101
|
}
|
|
1102
|
+
for (const disclosure of ctx.__iamDisclosures) {
|
|
1103
|
+
const variableKey=ctx.__iamVariableKeys[disclosure.label];if(!variableKey)continue;
|
|
1104
|
+
ctx.__iamPropHandlers.set(disclosure.name,{variableKey,value:disclosure.op==='toggle'?{op:'not',arg:{op:'var',key:variableKey}}:{op:'const',value:disclosure.op==='open'},payload:{}});
|
|
1105
|
+
}
|
|
1042
1106
|
// Rebind pure local records after scalar state identities exist. This preserves
|
|
1043
1107
|
// useMemo/context field relationships without invoking a hook or callback.
|
|
1044
1108
|
for(const [name,expression]of ctx.__iamLocals){
|
|
@@ -1126,6 +1190,7 @@ export async function analyze({
|
|
|
1126
1190
|
}
|
|
1127
1191
|
function uiHandler(initializer, owner, ctx, property = '') {
|
|
1128
1192
|
let fn = initializer && ts.isJsxExpression(initializer) ? unwrap(initializer.expression) : null;
|
|
1193
|
+
if(fn&&ts.isPropertyAccessExpression(fn)&&ctx.__iamPropHandlers.has(fn.getText(owner.module.source)))return ctx.__iamPropHandlers.get(fn.getText(owner.module.source));
|
|
1129
1194
|
const eventValue = (variableKey) => ({ variableKey, value: {op:'event',key:'value'}, payload:{value:ui.variables.find(v=>v.variableKey===variableKey)?.valueType} });
|
|
1130
1195
|
if(fn&&ts.isIdentifier(fn)&&ctx.__iamPropHandlers.has(fn.text))return ctx.__iamPropHandlers.get(fn.text);
|
|
1131
1196
|
if(fn&&ts.isIdentifier(fn)&&ctx.__iamSetters[fn.text]&&['onValueChange','onOpenChange'].includes(property)) {
|
|
@@ -1136,7 +1201,7 @@ export async function analyze({
|
|
|
1136
1201
|
const props=ctx[fn.expression.text],handler=props&&typeof props==='object'&&forwarded.get(props)?.handlers.find(h=>h.key===fn.name.text);
|
|
1137
1202
|
if(handler)return handler;
|
|
1138
1203
|
}
|
|
1139
|
-
if(!fn||!ts.isArrowFunction(fn)||fn.modifiers?.some(m=>m.kind===ts.SyntaxKind.AsyncKeyword))return null;
|
|
1204
|
+
if(!fn||![ts.isArrowFunction,ts.isFunctionExpression,ts.isFunctionDeclaration].some(is=>is(fn))||fn.modifiers?.some(m=>m.kind===ts.SyntaxKind.AsyncKeyword))return null;
|
|
1140
1205
|
let statements=ts.isBlock(fn.body)?[...fn.body.statements]:[fn.body];
|
|
1141
1206
|
if(statements.length>16)return null;
|
|
1142
1207
|
const writes=[],payload={};
|
|
@@ -1181,13 +1246,14 @@ export async function analyze({
|
|
|
1181
1246
|
ts,
|
|
1182
1247
|
node,
|
|
1183
1248
|
module: owner.module,
|
|
1184
|
-
locals: ctx.__iamLocals,
|
|
1249
|
+
locals: new Map([...ctx.__iamLocals,...ctx.__iamQueryLocals]),
|
|
1185
1250
|
binding,
|
|
1186
1251
|
functionFrom,
|
|
1187
1252
|
imported: externalImport,
|
|
1188
1253
|
});
|
|
1189
1254
|
}
|
|
1190
1255
|
function remoteResultCondition(node, owner, ctx) {
|
|
1256
|
+
if (queryBacked(node, owner, ctx)) return 'remote';
|
|
1191
1257
|
let shape = false;
|
|
1192
1258
|
const root =
|
|
1193
1259
|
ts.isIdentifier(node) && ctx.__iamLocals.has(node.text)
|
|
@@ -1224,7 +1290,7 @@ export async function analyze({
|
|
|
1224
1290
|
next[key] = evalExpression(init, owner.module, next);
|
|
1225
1291
|
return next;
|
|
1226
1292
|
}
|
|
1227
|
-
function finiteCollection(node, owner, ctx, instance,
|
|
1293
|
+
function finiteCollection(node, owner, ctx, instance, _depth) {
|
|
1228
1294
|
if (ctx.__iamCollectionTemplate || !ts.isConditionalExpression(node))
|
|
1229
1295
|
return null;
|
|
1230
1296
|
const maps = [];
|
|
@@ -1484,6 +1550,12 @@ export async function analyze({
|
|
|
1484
1550
|
if (!node) return "";
|
|
1485
1551
|
if (depth > 45) { gap("RENDER_DEPTH_LIMIT", owner.module.file, owner.symbol + ": JSX traversal budget exceeded"); return ""; }
|
|
1486
1552
|
const m = owner.module;
|
|
1553
|
+
if(ts.isCallExpression(node)&&ts.isIdentifier(node.expression)&&ctx.__iamLocals.has(node.expression.text)){
|
|
1554
|
+
const fn=unwrap(ctx.__iamLocals.get(node.expression.text));
|
|
1555
|
+
if(fn&&ts.isArrowFunction(fn)&&!fn.modifiers?.some(v=>v.kind===ts.SyntaxKind.AsyncKeyword)&&!ts.isBlock(fn.body)&&hasSourceJsx(fn.body)&&fn.parameters.length<=8&&fn.parameters.every(p=>ts.isIdentifier(p.name)&&!p.dotDotDotToken)&&!node.arguments.some(ts.isSpreadElement)){
|
|
1556
|
+
return renderInvocation({callback:{fn,owner,ctx,instance:instance+'/source-helper'},args:node.arguments.map(arg=>evalExpression(arg,m,ctx)),caller:ctx},instance,depth+1);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1487
1559
|
const collection=finiteCollection(node,owner,ctx,instance,depth);if(collection!==null)return collection;
|
|
1488
1560
|
if(ts.isIdentifier(node)&&ctx.__iamLocals.has(node.text)&&hasSourceJsx(ctx.__iamLocals.get(node.text))){
|
|
1489
1561
|
if(ctx.__iamActiveJsx?.has(node.text))return '';
|
|
@@ -1602,7 +1674,7 @@ export async function analyze({
|
|
|
1602
1674
|
const elementKey=identity('element',{component:owner.key,state:label,unobserved:index,sourceOffset:condition.getStart(m.source)-owner.fn.getStart(m.source)}),id=identity('node',{page:pageKey,element:elementKey,instance:instance+'/unobserved-'+index}),source=sourceLocation(m,condition,owner.symbol);
|
|
1603
1675
|
record.set(id,{elementKey,source,synthetic:true});
|
|
1604
1676
|
elements.set(elementKey,{elementKey,componentKey:owner.key,tag:'div',source,identityStrategy:'provisional_ast_ordinal',editableProperties:[],binding:'preview_only'});
|
|
1605
|
-
return '<div data-iam-node="'+id+'" data-iam-unobserved="true" hidden="" data-iam-condition="'+conditionRow.conditionKey+'" data-iam-alternative="'+(index===0)+'">'+renderExpr(branch,owner,ctx,instance+'/unobserved-'+index,depth+1)+'</div>';
|
|
1677
|
+
return '<div data-iam-node="'+id+'" data-iam-unobserved="true" hidden="" data-iam-condition="'+conditionRow.conditionKey+'" data-iam-alternative="'+(index===0)+'" class="iam-state">'+renderExpr(branch,owner,ctx,instance+'/unobserved-'+index,depth+1)+'</div>';
|
|
1606
1678
|
}).join('');
|
|
1607
1679
|
}
|
|
1608
1680
|
if (
|
|
@@ -1617,15 +1689,7 @@ export async function analyze({
|
|
|
1617
1689
|
fn &&
|
|
1618
1690
|
(ts.isArrowFunction(fn) || ts.isFunctionExpression(fn))
|
|
1619
1691
|
) {
|
|
1620
|
-
const limit=ctx.__iamCollectionTemplate?128:50;
|
|
1621
|
-
if (values.length > limit)
|
|
1622
|
-
gap(
|
|
1623
|
-
"COLLECTION_TRUNCATED",
|
|
1624
|
-
m.file,
|
|
1625
|
-
"Static collection limited to 50 preview items",
|
|
1626
|
-
);
|
|
1627
1692
|
return values
|
|
1628
|
-
.slice(0, limit)
|
|
1629
1693
|
.map((value, i) => {
|
|
1630
1694
|
const next = { ...ctx };
|
|
1631
1695
|
if (fn.parameters[0] && ts.isIdentifier(fn.parameters[0].name))
|
|
@@ -1681,8 +1745,6 @@ export async function analyze({
|
|
|
1681
1745
|
}
|
|
1682
1746
|
return "";
|
|
1683
1747
|
}
|
|
1684
|
-
if (++renderedCount > 12000)
|
|
1685
|
-
throw new Error("Rendered node budget exceeded");
|
|
1686
1748
|
const opening = ts.isJsxElement(node) ? node.openingElement : node,
|
|
1687
1749
|
tag = opening.tagName.getText(m.source),
|
|
1688
1750
|
props = m.anchors.get(opening) ? { "data-indiana-id": m.anchors.get(opening) } : {}, uiHandlers = [], uiBindings = [], forwardedHandlers=[],uiAttributes=[];
|
|
@@ -1714,7 +1776,7 @@ export async function analyze({
|
|
|
1714
1776
|
}
|
|
1715
1777
|
for (let i = uiBindings.length - 1; i >= 0; i--) if (uiBindings[i].property === key) uiBindings.splice(i, 1);
|
|
1716
1778
|
for (let i = uiHandlers.length - 1; i >= 0; i--) if (uiHandlers[i].key === key) uiHandlers.splice(i, 1);
|
|
1717
|
-
if (["onClick", "onChange", "onInput", "onValueChange", "onOpenChange"].includes(key)) {
|
|
1779
|
+
if (["onClick", "onChange", "onInput", "onValueChange", "onOpenChange", "onClose"].includes(key)) {
|
|
1718
1780
|
props[key] = undefined;
|
|
1719
1781
|
const supported = ctx.__iamCollectionTemplate?null:uiHandler(attr.initializer, owner, ctx, key);
|
|
1720
1782
|
if (supported) { props[key] = undefined; uiHandlers.push({ ...supported, key, source: sourceLocation(m, attr, owner.symbol) }); }
|
|
@@ -1804,7 +1866,7 @@ export async function analyze({
|
|
|
1804
1866
|
elements.set(elementKey,{elementKey,componentKey:owner.key,tag:item.tag,source,identityStrategy:'provisional_ast_ordinal',editableProperties:[],binding:'preview_only'});record.set(nodeId,{elementKey,source,synthetic:true});
|
|
1805
1867
|
return '<'+item.tag+' data-iam-node="'+nodeId+'" '+Object.entries(item.attrs).map(([k,v])=>k+'="'+escape(v)+'"').join(' ')+'>'+item.children.map((child,i)=>draw(child,part+'/'+i)).join('')+'</'+item.tag+'>';
|
|
1806
1868
|
};
|
|
1807
|
-
return draw({tag:'svg',attrs:{xmlns:'http://www.w3.org/2000/svg',viewBox:'0 0 '+chart.width+' '+chart.height,width:chart.width,height:chart.height,role:'img','aria-label':chart.unobserved?'Chart: data unobserved':'Source chart projection','data-iam-chart':chart.unobserved?'unobserved':'source',style:'display:block;width:100%;height:
|
|
1869
|
+
return draw({tag:'svg',attrs:{xmlns:'http://www.w3.org/2000/svg',viewBox:'0 0 '+chart.width+' '+chart.height,width:chart.width,height:chart.height,role:'img','aria-label':chart.unobserved?'Chart: data unobserved':'Source chart projection','data-iam-chart':chart.unobserved?'unobserved':'source',style:'display:block;width:100%;height:100%;max-height:'+chart.height+'px'},children:chart.children},'root');
|
|
1808
1870
|
}
|
|
1809
1871
|
const sourceIcon=evalExpression(opening.tagName,m,ctx);
|
|
1810
1872
|
if(sourceIcon?.[LUCIDE_SOURCE])return renderLucide(sourceIcon,node,owner,props,instance,!ctx.__iamCollectionTemplate);
|
|
@@ -1813,8 +1875,8 @@ export async function analyze({
|
|
|
1813
1875
|
let childCtx=ctx,tabGroup=ctx.__iamTabs;
|
|
1814
1876
|
const provider=tag.endsWith('.Provider')?contextKey(m,tag.slice(0,-9)):contextKey(m,tag);
|
|
1815
1877
|
if(provider){const contexts=new Map(ctx.__iamContexts);contexts.set(provider,props.value);childCtx={...childCtx,__iamContexts:contexts};}
|
|
1816
|
-
if(overlay&&['Root','SubmenuRoot'].includes(overlay.part)){
|
|
1817
|
-
const openProperty=overlay.family==='Transition'?'in':'open',open=props[openProperty];
|
|
1878
|
+
if(overlay&&(['Root','SubmenuRoot'].includes(overlay.part)||overlay.family==='AriaDialog'&&['Backdrop','Popup'].includes(overlay.part)&&(Object.hasOwn(props,'isOpen')||Object.hasOwn(props,'defaultOpen')))){
|
|
1879
|
+
const openProperty=overlay.family==='Transition'?'in':overlay.family==='AriaDialog'?'isOpen':'open',open=props[openProperty];
|
|
1818
1880
|
overlayGroup={open:open===true||open===undefined&&props.defaultOpen===true,variable:uiBindings.find(b=>b.property===openProperty)?.value,controller:uiHandlers.find(h=>h.key==='onOpenChange')};
|
|
1819
1881
|
if(overlay.family!=='Transition'&&open===undefined&&!props.__iamOpaqueProps&&(props.defaultOpen===undefined||typeof props.defaultOpen==='boolean')){
|
|
1820
1882
|
const scopeKey=identity('primitive-state',{page:pageKey,instance,family:overlay.family}),variableKey=identity('ui-variable',{scope:scopeKey,label:'open'});
|
|
@@ -1844,15 +1906,50 @@ export async function analyze({
|
|
|
1844
1906
|
}
|
|
1845
1907
|
if(tabPart==='Root') {
|
|
1846
1908
|
const valueBinding=uiBindings.find(b=>b.property==='value')?.value;
|
|
1847
|
-
const controller=uiHandlers.find(h=>h.key==='onValueChange');
|
|
1909
|
+
const controller=uiHandlers.find(h=>h.key==='onValueChange'||basePart?.mantine&&h.key==='onChange');
|
|
1848
1910
|
tabGroup={tabKey:identity('ui-tab',{page:pageKey,scope:ctx.__iamScope,instance}),routeKey:pageKey,renderKey:'pending',nodeId:'pending',variableKey:valueBinding?.op==='var'?valueBinding.key:null,initialValue:typeof props.value==='string'?props.value:typeof props.defaultValue==='string'?props.defaultValue:null,items:[],source:sourceLocation(m,node,owner.symbol),scopeSource:ui.variables.find(v=>v.variableKey===valueBinding?.key)?.source??sourceLocation(m,node,owner.symbol),controller};
|
|
1849
1911
|
childCtx={...childCtx,__iamTabs:tabGroup};
|
|
1850
1912
|
}
|
|
1913
|
+
const mantineRef=m.imports.get(tag.split('.')[0]),mantineName=mantineRef?.specifier==='@mantine/core'?(mantineRef.name==='*'?tag.split('.').slice(1).join('.'):mantineRef.name+tag.split('.').slice(1).map(s=>'.'+s).join('')):null;
|
|
1914
|
+
let accordion=ctx.__iamContexts?.get('$iam-mantine-accordion');
|
|
1915
|
+
if(mantineName==='Accordion'){
|
|
1916
|
+
const contexts=new Map(childCtx.__iamContexts);accordion={value:props.value??props.defaultValue,multiple:props.multiple===true,name:identity('accordion',{page:pageKey,instance}),classes:props.classNames};contexts.set('$iam-mantine-accordion',accordion);childCtx={...childCtx,__iamContexts:contexts};
|
|
1917
|
+
gap('ACCORDION_SOURCE_PREVIEW',m.file,'Native local details/summary preview; source defaults are retained and library callbacks are not executed.');
|
|
1918
|
+
}
|
|
1919
|
+
if(mantineName==='Accordion.Item'&&accordion){props.open=Array.isArray(accordion.value)?accordion.value.includes(props.value):typeof props.value==='string'&&accordion.value===props.value;if(!accordion.multiple)props.name=accordion.name;}
|
|
1920
|
+
if(mantineName?.startsWith('Accordion.')&&accordion){const field={Item:'item',Control:'control',Panel:'panel'}[mantineName.split('.')[1]],name=accordion.classes?.[field];if(typeof name==='string')props.className=[props.className,name].filter(v=>typeof v==='string').join(' ');}
|
|
1851
1921
|
const localRef=componentBinding(m,tag),localTarget=ctx[tag]?.[COMPONENT]??(localRef&&componentDefs.get(localRef.module.file+'#'+localRef.name));
|
|
1852
1922
|
const dynamicNode=ctx.__iamLocals.get(tag);
|
|
1853
1923
|
const registry=!localTarget&&dynamicNode?componentRegistry({ts,node:dynamicNode,module:m,locals:ctx.__iamLocals,binding,functionFrom,value:(n,module)=>evalExpression(n,module,ctx),component:(n,module)=>sourceComponent(n,module)?.[COMPONENT],variable:name=>ctx.__iamVariableKeys[name]??(ctx.__iamPropBindings.get(name)?.op==='var'?ctx.__iamPropBindings.get(name).key:null),location:sourceLocation,unknown:UNKNOWN,imported:externalImport}):null;
|
|
1854
1924
|
const renderChildren=(inherited=childCtx)=>ts.isJsxElement(node)?node.children.map((child,i)=>renderExpr(child,owner,{...childCtx,__iamContexts:inherited.__iamContexts??childCtx.__iamContexts,__iamTabs:inherited.__iamTabs??childCtx.__iamTabs,__iamOverlays:inherited.__iamOverlays??childCtx.__iamOverlays},instance+'/child-'+i,depth+1)).join(''):props.children?.iamRenderChildren?props.children.iamRenderChildren(inherited):props.children?.iamChildren||'';
|
|
1855
|
-
|
|
1925
|
+
let children = localTarget||registry ? '' : renderChildren();
|
|
1926
|
+
const mantine = mantinePrimitive(m.imports.get(tag.split('.')[0]), props, tag.split('.').slice(1).join('.'));
|
|
1927
|
+
if (mantine) {
|
|
1928
|
+
gap('MANTINE_SOURCE_PROFILE', m.file, 'Inert semantic Mantine projection; theme resolution, portals, focus management and library callbacks are not executed.');
|
|
1929
|
+
if (mantine.transparent) return children;
|
|
1930
|
+
Object.assign(props, mantine.props);
|
|
1931
|
+
if (mantine.overlay) {
|
|
1932
|
+
const visible = uiBindings.find(b => b.property === 'opened');
|
|
1933
|
+
if (visible) uiBindings.push({...visible, property: 'visible'});
|
|
1934
|
+
if (typeof props.opened !== 'boolean') gap('MANTINE_OPEN_STATE_UNOBSERVED', m.file, 'Unknown overlay state is initially hidden; no runtime open state is inferred.');
|
|
1935
|
+
}
|
|
1936
|
+
}
|
|
1937
|
+
const flowbite=flowbiteShape(externalImport(m,tag),props,children,['Table','Navbar','Sidebar'].includes(m.imports.get(tag.split('.')[0])?.name)?tag.split('.')[1]:undefined,flowbiteTheme);
|
|
1938
|
+
if(flowbite){
|
|
1939
|
+
gap('UI_LIBRARY_STATIC_PROFILE',m.file,'Flowbite 0.3 inert presentation profile; custom theme and library state remain unobserved.');
|
|
1940
|
+
const source=sourceLocation(m,node,owner.symbol);
|
|
1941
|
+
const draw=(item,part)=>{
|
|
1942
|
+
if(typeof item==='string')return escape(item);
|
|
1943
|
+
if(Object.hasOwn(item,'html'))return item.html;
|
|
1944
|
+
const elementKey=identity('element',{component:owner.key,library:'flowbite',offset:node.pos,part}),nodeId=identity('node',{page:pageKey,elementKey,instance});
|
|
1945
|
+
elements.set(elementKey,{elementKey,componentKey:owner.key,tag:item.tag,source,identityStrategy:'provisional_ast_ordinal',editableProperties:[],binding:'preview_only'});record.set(nodeId,{elementKey,source,synthetic:true});
|
|
1946
|
+
if(item.attrs.class)item.attrs.class.split(/\s+/).filter(Boolean).forEach(c=>allClasses.add(c));
|
|
1947
|
+
if(item.attrs.src)assets.set(item.attrs.src,null);
|
|
1948
|
+
const attrs=Object.entries(item.attrs).filter(([,v])=>v!==false).map(([k,v])=>' '+k+'="'+escape(v===true?'':v)+'"').join('');
|
|
1949
|
+
return '<'+item.tag+' data-iam-node="'+nodeId+'"'+attrs+'>'+(voidTags.has(item.tag)?'':item.children.map((child,i)=>draw(child,part+'/'+i)).join('')+'</'+item.tag+'>');
|
|
1950
|
+
};
|
|
1951
|
+
return draw(flowbite,'root');
|
|
1952
|
+
}
|
|
1856
1953
|
|
|
1857
1954
|
// Project the documented Controller render callback from source, with no
|
|
1858
1955
|
// form initialization, live field values or business callback execution.
|
|
@@ -1897,7 +1994,8 @@ export async function analyze({
|
|
|
1897
1994
|
props["data-iam-adapter"] = tag;
|
|
1898
1995
|
}
|
|
1899
1996
|
if (/^[A-Z]/.test(tag) && !intrinsicAlias) {
|
|
1900
|
-
if(
|
|
1997
|
+
if (mantine) htmlTag = mantine.tag;
|
|
1998
|
+
else if(tabPart){
|
|
1901
1999
|
htmlTag=tabPart==='Tab'?'button':'div';
|
|
1902
2000
|
if(tabPart==='List')props.role='tablist';
|
|
1903
2001
|
if(tabPart==='Tab'){props.role='tab';props.type='button';props['aria-selected']=tabGroup?.initialValue===props.value;}
|
|
@@ -1907,14 +2005,24 @@ export async function analyze({
|
|
|
1907
2005
|
htmlTag=['Trigger','Close','Item','CheckboxItem','RadioItem','SubmenuTrigger'].includes(overlay.part)&&props.asChild!==true?'button':overlay.part==='Title'?'h2':overlay.part==='Description'?'p':'div';
|
|
1908
2006
|
if(htmlTag==='button')props.type='button';
|
|
1909
2007
|
if(['Portal','Popup','Backdrop'].includes(overlay.part)||overlay.family==='Transition'){props.hidden=!overlayGroup?.open;if(overlayGroup?.condition){props['data-iam-condition']=overlayGroup.condition.conditionKey;props['data-iam-alternative']='true';props['data-iam-condition-default']='false';props['data-iam-unobserved']='true';}if(overlayGroup?.variable)uiBindings.push({property:'visible',value:overlayGroup.variable,source:sourceLocation(m,node,owner.symbol)});}
|
|
1910
|
-
if(
|
|
1911
|
-
if(
|
|
2008
|
+
if(overlay.rootVisibility){props.hidden=!overlayGroup?.open;if(overlayGroup?.variable)uiBindings.push({property:'visible',value:overlayGroup.variable,source:sourceLocation(m,node,owner.symbol)});}
|
|
2009
|
+
else if(['Root','SubmenuRoot','Portal','Provider'].includes(overlay.part)||props.asChild===true)props.style={display:'contents'};
|
|
2010
|
+
if(overlay.part==='Popup'&&overlay.role!==null)props.role=overlay.role??(overlay.family==='Menu'?'menu':overlay.family==='Tooltip'?'tooltip':'dialog');
|
|
2011
|
+
if(overlay.part==='Content'&&overlay.role)props.role=overlay.role;
|
|
1912
2012
|
}
|
|
1913
2013
|
else if (tag === "Link" || ["react-router", "react-router-dom", "@tanstack/react-router"].includes(routerPrimitive?.specifier) && ["Link", "NavLink"].includes(routerPrimitive.name)) {
|
|
1914
2014
|
htmlTag = "a";
|
|
1915
2015
|
if (typeof props.to === "string") props.href = props.to;
|
|
1916
2016
|
}
|
|
1917
2017
|
else if (tag === "Image") htmlTag = "img";
|
|
2018
|
+
else if(externalImport(m,tag)?.specifier==='recharts'&&externalImport(m,tag)?.name==='ResponsiveContainer'){
|
|
2019
|
+
htmlTag='div';const dimension=v=>typeof v==='number'&&Number.isFinite(v)||typeof v==='string'&&/^[0-9.]+(?:%|px|rem|vh|vw)?$/.test(v)?v:'100%';props.style={...(props.style&&typeof props.style==='object'?props.style:{}),width:dimension(props.width),height:dimension(props.height),minWidth:0};gap('RESPONSIVE_CHART_SOURCE_PREVIEW',m.file,'Static chart viewport follows its declared container; library measurements, effects and animation are not executed.');
|
|
2020
|
+
}
|
|
2021
|
+
else if((['@base-ui/react/avatar','@base-ui/react'].includes(m.imports.get(tag.split('.')[0])?.specifier)&&m.imports.get(tag.split('.')[0]).name==='Avatar'&&['Root','Image','Fallback'].includes(tag.split('.')[1]))||(m.imports.get(tag.split('.')[0])?.specifier==='@radix-ui/react-avatar'&&['Image','AvatarImage','Root','Avatar','Fallback','AvatarFallback'].includes(externalImport(m,tag)?.name))){
|
|
2022
|
+
const part=tag.split('.')[1]??externalImport(m,tag)?.name;
|
|
2023
|
+
htmlTag=['Image','AvatarImage'].includes(part)?'img':'span';
|
|
2024
|
+
if(['Fallback','AvatarFallback'].includes(part)){props.hidden=true;gap('AVATAR_FALLBACK_UNOBSERVED',m.file,'Packaged image is the preview; merchant image loading/error fallback state is not simulated.');}
|
|
2025
|
+
}
|
|
1918
2026
|
else if(m.imports.get(tag)?.specifier==='react-basics'&&m.imports.get(tag)?.name==='Text'){
|
|
1919
2027
|
htmlTag=typeof props.as==='string'&&allowedTags.has(props.as)?props.as:'span';
|
|
1920
2028
|
gap('COMPONENT_STYLE_ADAPTER',m.file,'react-basics Text DOM semantics only; actual styles need runtime evidence');
|
|
@@ -2020,7 +2128,7 @@ export async function analyze({
|
|
|
2020
2128
|
record.set(nodeId, {
|
|
2021
2129
|
elementKey,
|
|
2022
2130
|
source,
|
|
2023
|
-
synthetic: htmlTag !== tag && tag !== "Link" && tag !== "Image"&&!intrinsicAlias&&!knownExternalPrimitive,
|
|
2131
|
+
synthetic: Boolean(m.mdx) || htmlTag !== tag && tag !== "Link" && tag !== "Image"&&!intrinsicAlias&&!knownExternalPrimitive,
|
|
2024
2132
|
});
|
|
2025
2133
|
if(tabPart==='Root'){
|
|
2026
2134
|
// Tab initialization below shares the same concrete source container.
|
|
@@ -2042,7 +2150,7 @@ export async function analyze({
|
|
|
2042
2150
|
if(tabGroup.controller){const writes=(tabGroup.controller.writes||[{variableKey:tabGroup.controller.variableKey,value:tabGroup.controller.value}]).map(w=>({...w,value:replace(w.value)}));uiHandlers.push({...writes[0],writes,key:'onClick',payload:{},source});}
|
|
2043
2151
|
}
|
|
2044
2152
|
if(tabPart==='Panel'&&tabGroup?.variableKey&&typeof props.value==='string')uiBindings.push({property:'visible',value:{op:'eq',left:{op:'var',key:tabGroup.variableKey},right:{op:'const',value:props.value}},source});
|
|
2045
|
-
for (const handler of uiHandlers.filter(h=>!['onValueChange','onOpenChange'].includes(h.key))) {
|
|
2153
|
+
for (const handler of uiHandlers.filter(h=>!['onValueChange','onOpenChange','onClose'].includes(h.key)&&!(tabPart==='Root'&&h.key==='onChange'))) {
|
|
2046
2154
|
const event = handler.key === "onClick" ? "click" : htmlTag === "select" || handler.payload.checked ? "change" : "input";
|
|
2047
2155
|
const writes=handler.writes||[{variableKey:handler.variableKey,value:handler.value}];
|
|
2048
2156
|
ui.transitions.push({ transitionKey: identity("ui-transition", { page: pageKey, node: nodeId, event }), routeKey: pageKey, fromStateKey: "pending", toStateKey: "pending", trigger: { nodeId, event, payload: handler.payload }, guard: { op: "const", value: true }, stateReads: [...new Set(writes.flatMap(w=>readVariables(w.value)))].sort(), stateWrites: writes, simulation: "implemented", evidence: "source_inferred", source: handler.source });
|
|
@@ -2056,14 +2164,22 @@ export async function analyze({
|
|
|
2056
2164
|
}
|
|
2057
2165
|
ui.bindings.push({ bindingKey: identity("ui-binding", { node: nodeId, property: binding.property }), routeKey: pageKey, nodeId, elementKey, ...binding });
|
|
2058
2166
|
}
|
|
2059
|
-
const sensitiveInput = htmlTag ===
|
|
2167
|
+
const sensitiveInput = ['input', 'textarea', 'select'].includes(htmlTag) && (htmlTag === 'input' && ["password", "hidden"].includes(String(props.type).toLowerCase()) || sensitiveName(String(props.name || props.id || "")));
|
|
2060
2168
|
if (sensitiveInput) {
|
|
2061
2169
|
delete props.value; delete props.defaultValue;
|
|
2170
|
+
if (htmlTag === 'textarea') children = '';
|
|
2062
2171
|
ui.bindings = ui.bindings.filter(b => b.nodeId !== nodeId);
|
|
2063
2172
|
ui.transitions = ui.transitions.filter(t => t.trigger.nodeId !== nodeId);
|
|
2064
2173
|
gap("SENSITIVE_INPUT_REDACTED", m.file, "Input value and state bridge omitted");
|
|
2065
2174
|
}
|
|
2175
|
+
if (['input', 'textarea', 'select'].includes(htmlTag) && !Object.hasOwn(props, 'value') && Object.hasOwn(props, 'defaultValue')) props.value = props.defaultValue;
|
|
2176
|
+
if (htmlTag === 'input' && !Object.hasOwn(props, 'checked') && typeof props.defaultChecked === 'boolean') props.checked = props.defaultChecked;
|
|
2177
|
+
if (htmlTag === 'textarea' && ['string', 'number'].includes(typeof props.value)) children = escape(props.value);
|
|
2066
2178
|
const attrs = { "data-iam-node": nodeId,...(['input','textarea','select'].includes(htmlTag)&&Object.hasOwn(props,'value')&&isUnknown(props.value)?{'data-iam-input-unobserved':'true'}:{}) };
|
|
2179
|
+
if(mantine?.overlay){
|
|
2180
|
+
const close=uiHandlers.find(h=>h.key==='onClose');
|
|
2181
|
+
if(close){const closeId=identity('node',{page:pageKey,element:elementKey,instance,mantineClose:true});record.set(closeId,{elementKey,source,synthetic:true});const writes=close.writes||[{variableKey:close.variableKey,value:close.value}];ui.transitions.push({transitionKey:identity('ui-transition',{page:pageKey,node:closeId,event:'click'}),routeKey:pageKey,fromStateKey:'pending',toStateKey:'pending',trigger:{nodeId:closeId,event:'click',payload:{}},guard:{op:'const',value:true},stateReads:[...new Set(writes.flatMap(w=>readVariables(w.value)))].sort(),stateWrites:writes,simulation:'implemented',evidence:'source_inferred',source:close.source});children='<button type="button" aria-label="Close dialog" data-iam-node="'+closeId+'">×</button>'+children;}
|
|
2182
|
+
}
|
|
2067
2183
|
for (const [key, value] of Object.entries(props)) {
|
|
2068
2184
|
if (key === "style") {
|
|
2069
2185
|
const css = staticStyle(value, () => gap("INLINE_STYLE_UNSUPPORTED", m.file,
|
|
@@ -2077,12 +2193,17 @@ export async function analyze({
|
|
|
2077
2193
|
gap("PRIVATE_URL_REDACTED", m.file, "URL credentials or sensitive query omitted");
|
|
2078
2194
|
continue;
|
|
2079
2195
|
}
|
|
2080
|
-
if (["disabled", "hidden", "checked"].includes(key) && value === false) continue;
|
|
2196
|
+
if (["disabled", "hidden", "checked", "required", "readOnly", "multiple", "selected", "open"].includes(key) && value === false) continue;
|
|
2081
2197
|
const attr =
|
|
2082
2198
|
{
|
|
2083
2199
|
className: "class",
|
|
2084
2200
|
htmlFor: "for",
|
|
2085
2201
|
tabIndex: "tabindex",
|
|
2202
|
+
readOnly: "readonly",
|
|
2203
|
+
minLength: "minlength",
|
|
2204
|
+
maxLength: "maxlength",
|
|
2205
|
+
autoComplete: "autocomplete",
|
|
2206
|
+
inputMode: "inputmode",
|
|
2086
2207
|
viewBox: "viewBox",
|
|
2087
2208
|
strokeWidth: "stroke-width",
|
|
2088
2209
|
strokeLinecap: "stroke-linecap",
|
|
@@ -2091,7 +2212,7 @@ export async function analyze({
|
|
|
2091
2212
|
clipRule: "clip-rule",
|
|
2092
2213
|
}[key] || key;
|
|
2093
2214
|
if (
|
|
2094
|
-
!/^(?:class|id|name|type|placeholder|value|title|alt|href|src|role|for|disabled|hidden|checked|width|height|viewBox|d|fill|stroke|stroke-width|stroke-linecap|stroke-linejoin|fill-rule|clip-rule|cx|cy|r|x|y|x1|x2|y1|y2|points|aria-[a-z-]+|data-indiana-id|data-indiana-map-(?:area|flow|kind|auth|edge)|data-(?:slot|state|side|variant|collapsible|orientation|active)|data-testid|data-test|data-qa|data-iam-(?:adapter|toggle|tab-value|tab-key|condition|alternative|condition-default|unobserved))$/.test(
|
|
2215
|
+
!/^(?:class|id|name|type|placeholder|value|title|alt|href|src|role|for|disabled|hidden|checked|required|readonly|multiple|selected|open|start|min|max|step|minlength|maxlength|pattern|autocomplete|inputmode|rows|cols|width|height|viewBox|d|fill|stroke|stroke-width|stroke-linecap|stroke-linejoin|fill-rule|clip-rule|cx|cy|r|x|y|x1|x2|y1|y2|points|aria-[a-z-]+|data-indiana-id|data-indiana-map-(?:area|flow|kind|auth|edge)|data-(?:slot|state|side|variant|collapsible|orientation|active)|data-testid|data-test|data-qa|data-iam-(?:adapter|toggle|tab-value|tab-key|condition|alternative|condition-default|unobserved))$/.test(
|
|
2095
2216
|
attr,
|
|
2096
2217
|
)
|
|
2097
2218
|
)
|
|
@@ -2107,6 +2228,7 @@ export async function analyze({
|
|
|
2107
2228
|
}
|
|
2108
2229
|
attrs["data-iam-external"] = "true";
|
|
2109
2230
|
} else if (attr === "src") {
|
|
2231
|
+
if(!['img','source'].includes(htmlTag)){gap('RESOURCE_HOST_UNSUPPORTED',m.file,tag+': resource attribute omitted from a non-image source adapter');continue;}
|
|
2110
2232
|
if (String(value).startsWith("/") && !String(value).startsWith("//"))
|
|
2111
2233
|
assets.set(String(value), null);
|
|
2112
2234
|
else {
|
|
@@ -2120,7 +2242,7 @@ export async function analyze({
|
|
|
2120
2242
|
.forEach((c) => allClasses.add(c));
|
|
2121
2243
|
attrs[attr] = String(value);
|
|
2122
2244
|
}
|
|
2123
|
-
|
|
2245
|
+
const rendered = (
|
|
2124
2246
|
"<" +
|
|
2125
2247
|
htmlTag +
|
|
2126
2248
|
Object.entries(attrs)
|
|
@@ -2131,6 +2253,12 @@ export async function analyze({
|
|
|
2131
2253
|
? (tag.startsWith("Icons.") ? "◇" : children) + "</" + htmlTag + ">"
|
|
2132
2254
|
: "")
|
|
2133
2255
|
);
|
|
2256
|
+
if (mantine?.label) {
|
|
2257
|
+
const labelId = identity('node', {page: pageKey, element: elementKey, instance, mantineLabel: true});
|
|
2258
|
+
record.set(labelId, {elementKey, source, synthetic: true});
|
|
2259
|
+
return '<label data-iam-node="' + labelId + '" style="display:flex;flex-direction:column;gap:0.35rem">' + '<span>' + escape(mantine.label) + '</span>' + rendered + '</label>';
|
|
2260
|
+
}
|
|
2261
|
+
return rendered;
|
|
2134
2262
|
}
|
|
2135
2263
|
function renderEntry(file, props, instance, symbol) {
|
|
2136
2264
|
const entryModule = modules.get(file), entryRef = entryModule && componentBinding(entryModule, symbol ?? entryModule.defaultName);
|
|
@@ -2296,7 +2424,7 @@ export async function analyze({
|
|
|
2296
2424
|
});
|
|
2297
2425
|
// Unknown source alternatives live in ui.conditions. Representable local
|
|
2298
2426
|
// state candidates remain separate from concrete source documents.
|
|
2299
|
-
for (const branch of branches.filter(b=>b.evidence==='source_inferred')
|
|
2427
|
+
for (const branch of branches.filter(b=>b.evidence==='source_inferred')) {
|
|
2300
2428
|
const key = identity("state", {page:pageKey,source:branch.source,label:branch.label});
|
|
2301
2429
|
if(!states.some(state=>state.stateKey===key)){
|
|
2302
2430
|
states.push({stateKey:key,pageKey,label:branch.label,evidence:branch.evidence,source:branch.source,documentKey:null});
|
|
@@ -2430,6 +2558,9 @@ export async function analyze({
|
|
|
2430
2558
|
);
|
|
2431
2559
|
css +=
|
|
2432
2560
|
"\n.iam-state{display:contents}.iam-state[hidden]{display:none!important}";
|
|
2561
|
+
let projectionCss = cssModules.css();
|
|
2562
|
+
if (documents.some(d=>d.html.includes('class="iam-state'))) projectionCss += "\n.iam-state{display:contents}.iam-state[hidden]{display:none!important}";
|
|
2563
|
+
if ([...modules.values()].some(m=>m.mdx)) projectionCss += '\n.iam-markdown{line-height:1.7}.iam-markdown p,.iam-markdown ul,.iam-markdown ol,.iam-markdown pre,.iam-markdown blockquote,.iam-markdown table{margin-block:1em}.iam-markdown h1,.iam-markdown h2,.iam-markdown h3{margin-block:1.2em .5em;font-weight:700;line-height:1.25}.iam-markdown h1{font-size:2em}.iam-markdown h2{font-size:1.5em}.iam-markdown h3{font-size:1.25em}.iam-markdown ul,.iam-markdown ol{padding-left:1.5em}.iam-markdown ul{list-style:disc}.iam-markdown ol{list-style:decimal}.iam-markdown pre{padding:1em;border-radius:.4em;background:#f1f5f9;color:#0f172a;overflow-x:auto;white-space:pre}.iam-markdown code{font-family:ui-monospace,monospace}.iam-markdown blockquote{padding-left:1em;border-left:3px solid #cbd5e1}.iam-markdown table{border-collapse:collapse}.iam-markdown th,.iam-markdown td{border:1px solid #cbd5e1;padding:.4em .7em}.iam-markdown a{text-decoration:underline}';
|
|
2433
2564
|
if (!pages.length)
|
|
2434
2565
|
throw new Error(
|
|
2435
2566
|
"No supported source routes found. Use Next App Router, Next Pages Router or a statically declared React Router route tree.",
|
|
@@ -2458,7 +2589,7 @@ export async function analyze({
|
|
|
2458
2589
|
schemaVersion: 2,
|
|
2459
2590
|
producer: {
|
|
2460
2591
|
name: "indiana-app-manifest-local",
|
|
2461
|
-
version: "0.
|
|
2592
|
+
version: "0.27.0",
|
|
2462
2593
|
method: "typescript-ast-and-bounded-static-projection;lucide-static-"+LUCIDE_SOURCE_VERSION,
|
|
2463
2594
|
},
|
|
2464
2595
|
app: { name, platforms: ["web"] },
|
|
@@ -2499,6 +2630,7 @@ export async function analyze({
|
|
|
2499
2630
|
const sourceGaps=new Map();
|
|
2500
2631
|
for(const row of ui.uncovered){const key=JSON.stringify([row.routeKey,row.source,row.event,row.reason]);const prior=sourceGaps.get(key);if(prior)prior.nodeId=null;else sourceGaps.set(key,{...row});}
|
|
2501
2632
|
ui.uncovered=[...sourceGaps.values()];
|
|
2633
|
+
attachSourceStyles(manifest, projectionCss);
|
|
2502
2634
|
manifest.routeTree = assembleRouteTree(manifest, ui, renderDefinitions, compositions.navigation);
|
|
2503
2635
|
presentation.conditions=[...new Map(presentation.conditions.map(c=>[c.conditionKey,c])).values()];
|
|
2504
2636
|
presentation.regions=presentation.regions.filter(r=>concrete.has(r.nodeId)&&r.options.every(o=>concrete.has(o.nodeId)));
|