11import type { CreateDataTableInput , DataField , DataTable , DataSelectOption } from '@core/data/schemas'
22import type { ImportFragment } from '@core/htmlImport'
3- import type { Page , PageNode } from '@core/page-tree'
4- import { createNode } from '@core/page-tree'
3+ import { createNode , flattenSubtree , getParent , type Page , type PageNode } from '@core/page-tree'
54import { formDisplayName , humanizeIdentifier , slugifyFormTableName } from './formSettingsNaming'
65
76export { formDisplayName } from './formSettingsNaming'
@@ -111,12 +110,11 @@ export function analyzeFormSettings(input: {
111110 return emptyAnalysis ( selectedNode , table )
112111 }
113112
114- const parentByNodeId = buildParentMap ( page )
115113 const formNode = selectedNode . moduleId === 'base.form'
116114 ? selectedNode
117- : nearestAncestorForm ( page , selectedNode . id , parentByNodeId )
115+ : nearestAncestorForm ( page , selectedNode . id )
118116 const form = formNode ? formSummary ( formNode ) : null
119- const inferredFields = formNode ? inferFieldsFromForm ( page , formNode , parentByNodeId ) : [ ]
117+ const inferredFields = formNode ? inferFieldsFromForm ( page , formNode ) : [ ]
120118 const missingFields = table && formNode ? fieldsMissingFromForm ( page , formNode , table ) : [ ]
121119 const kind = settingsKind ( selectedNode . moduleId )
122120 const warnings : FormSettingsWarning [ ] = [ ]
@@ -171,7 +169,7 @@ export function analyzeFormSettings(input: {
171169
172170 let inferredTarget : FormTargetSummary | null = null
173171 if ( kind === 'label' ) {
174- inferredTarget = inferLabelTarget ( page , selectedNode , parentByNodeId )
172+ inferredTarget = inferLabelTarget ( page , selectedNode )
175173 if ( ! inferredTarget ) {
176174 warnings . push ( {
177175 code : 'label_without_target' ,
@@ -351,7 +349,7 @@ function formSummary(node: PageNode): FormContextSummary {
351349function duplicateNameWarnings ( page : Page , formNode : PageNode ) : FormSettingsWarning [ ] {
352350 const seen = new Map < string , string > ( )
353351 const warnings : FormSettingsWarning [ ] = [ ]
354- for ( const nodeId of walkTree ( page , formNode . id ) ) {
352+ for ( const nodeId of flattenSubtree ( page , formNode . id ) ) {
355353 if ( nodeId === formNode . id ) continue
356354 const node = page . nodes [ nodeId ]
357355 if ( ! node || ! FORM_CONTROL_MODULES . has ( node . moduleId ) ) continue
@@ -373,15 +371,14 @@ function duplicateNameWarnings(page: Page, formNode: PageNode): FormSettingsWarn
373371function inferFieldsFromForm (
374372 page : Page ,
375373 formNode : PageNode ,
376- parentByNodeId : Map < string , string > ,
377374) : DataField [ ] {
378375 const fields : DataField [ ] = [ ]
379376 const usedIds = new Set < string > ( )
380- for ( const nodeId of walkTree ( page , formNode . id ) ) {
377+ for ( const nodeId of flattenSubtree ( page , formNode . id ) ) {
381378 if ( nodeId === formNode . id ) continue
382379 const node = page . nodes [ nodeId ]
383380 if ( ! node || ! FORM_CONTROL_MODULES . has ( node . moduleId ) ) continue
384- const field = inferFieldFromControl ( page , node , parentByNodeId , usedIds )
381+ const field = inferFieldFromControl ( page , node , usedIds )
385382 if ( field ) fields . push ( field )
386383 }
387384 return fields
@@ -390,10 +387,9 @@ function inferFieldsFromForm(
390387function inferFieldFromControl (
391388 page : Page ,
392389 node : PageNode ,
393- parentByNodeId : Map < string , string > ,
394390 usedIds : Set < string > ,
395391) : DataField | null {
396- const label = labelForControl ( page , node , parentByNodeId )
392+ const label = labelForControl ( page , node )
397393 const rawId = stringProp ( node , 'fieldId' , '' )
398394 || stringProp ( node , 'name' , '' )
399395 || stringProp ( node , 'id' , '' )
@@ -462,7 +458,7 @@ function inferFieldFromControl(
462458
463459function fieldsMissingFromForm ( page : Page , formNode : PageNode , table : DataTable ) : DataField [ ] {
464460 const representedFieldIds = new Set < string > ( )
465- for ( const nodeId of walkTree ( page , formNode . id ) ) {
461+ for ( const nodeId of flattenSubtree ( page , formNode . id ) ) {
466462 if ( nodeId === formNode . id ) continue
467463 const node = page . nodes [ nodeId ]
468464 if ( ! node || ! FORM_CONTROL_MODULES . has ( node . moduleId ) ) continue
@@ -475,10 +471,8 @@ function fieldsMissingFromForm(page: Page, formNode: PageNode, table: DataTable)
475471function labelForControl (
476472 page : Page ,
477473 node : PageNode ,
478- parentByNodeId : Map < string , string > ,
479474) : string {
480- const parentId = parentByNodeId . get ( node . id )
481- const parent = parentId ? page . nodes [ parentId ] : null
475+ const parent = getParent ( page , node . id )
482476 if ( parent ) {
483477 const nodeIndex = parent . children . indexOf ( node . id )
484478 for ( const siblingId of parent . children . slice ( 0 , nodeIndex ) . reverse ( ) ) {
@@ -510,7 +504,6 @@ function optionFieldsFromSelect(page: Page, selectNode: PageNode): DataSelectOpt
510504function inferLabelTarget (
511505 page : Page ,
512506 labelNode : PageNode ,
513- parentByNodeId : Map < string , string > ,
514507) : FormTargetSummary | null {
515508 const explicit = stringProp ( labelNode , 'targetId' , '' )
516509 if ( stringProp ( labelNode , 'targetMode' , 'auto' ) === 'explicit' && explicit ) {
@@ -520,12 +513,11 @@ function inferLabelTarget(
520513 : { nodeId : explicit , label : explicit }
521514 }
522515
523- const parentId = parentByNodeId . get ( labelNode . id )
524- const parent = parentId ? page . nodes [ parentId ] : null
516+ const parent = getParent ( page , labelNode . id )
525517 if ( ! parent ) return null
526518 const labelIndex = parent . children . indexOf ( labelNode . id )
527519 for ( const siblingId of parent . children . slice ( labelIndex + 1 ) ) {
528- for ( const candidateId of walkTree ( page , siblingId ) ) {
520+ for ( const candidateId of flattenSubtree ( page , siblingId ) ) {
529521 const candidate = page . nodes [ candidateId ]
530522 if ( candidate && FORM_CONTROL_MODULES . has ( candidate . moduleId ) ) {
531523 return { nodeId : candidate . id , label : controlLabel ( candidate ) }
@@ -535,41 +527,15 @@ function inferLabelTarget(
535527 return null
536528}
537529
538- function nearestAncestorForm (
539- page : Page ,
540- nodeId : string ,
541- parentByNodeId : Map < string , string > ,
542- ) : PageNode | null {
543- let currentId = parentByNodeId . get ( nodeId )
544- while ( currentId ) {
545- const current = page . nodes [ currentId ]
546- if ( ! current ) return null
530+ function nearestAncestorForm ( page : Page , nodeId : string ) : PageNode | null {
531+ let current = getParent ( page , nodeId )
532+ while ( current ) {
547533 if ( current . moduleId === 'base.form' ) return current
548- currentId = parentByNodeId . get ( current . id )
534+ current = getParent ( page , current . id )
549535 }
550536 return null
551537}
552538
553- function buildParentMap ( page : Page ) : Map < string , string > {
554- const map = new Map < string , string > ( )
555- for ( const node of Object . values ( page . nodes ) ) {
556- for ( const childId of node . children ) map . set ( childId , node . id )
557- }
558- return map
559- }
560-
561- function walkTree ( page : Page , startNodeId : string ) : string [ ] {
562- const out : string [ ] = [ ]
563- const visit = ( nodeId : string ) => {
564- const node = page . nodes [ nodeId ]
565- if ( ! node ) return
566- out . push ( nodeId )
567- for ( const childId of node . children ) visit ( childId )
568- }
569- visit ( startNodeId )
570- return out
571- }
572-
573539function stringProp ( node : PageNode , key : string , fallback : string ) : string {
574540 const value = node . props [ key ]
575541 return typeof value === 'string' ? value : fallback
0 commit comments