@@ -7,6 +7,7 @@ const path = require('path');
7
7
8
8
// Configuration
9
9
const PASSPORT_ROOT = './sample/Assets/Scripts/Passport' ;
10
+ const TUTORIALS_DIR = path . join ( PASSPORT_ROOT , '_tutorials' ) ;
10
11
const OUTPUT_DIR = './_parsed' ;
11
12
const OUTPUT_FILE = path . join ( OUTPUT_DIR , 'passport-features.json' ) ;
12
13
const FEATURES_JSON_PATH = path . join ( PASSPORT_ROOT , 'features.json' ) ;
@@ -23,138 +24,105 @@ try {
23
24
24
25
console . log ( 'Processing Passport features metadata...' ) ;
25
26
26
- // Load features.json to map script files to feature names
27
- const featuresMap = { } ;
27
+ // Load features.json to get feature groups and their features
28
+ let featureGroups = { } ;
28
29
try {
29
30
const featuresContent = fs . readFileSync ( FEATURES_JSON_PATH , 'utf8' ) ;
30
31
const featuresJson = JSON . parse ( featuresContent ) ;
31
-
32
- // Create mapping of script filename to feature name
33
- featuresJson . features . forEach ( ( feature ) => {
34
- const [ featureName , scriptFile ] = Object . entries ( feature ) [ 0 ] ;
35
- // Store both the full filename and just the filename without path
36
- featuresMap [ scriptFile ] = featureName ;
37
- featuresMap [ path . basename ( scriptFile ) ] = featureName ;
38
- } ) ;
32
+ featureGroups = featuresJson . features || { } ;
39
33
} catch ( error ) {
40
34
console . error ( `Error reading features.json: ${ error . message } ` ) ;
41
35
process . exit ( 1 ) ;
42
36
}
43
37
44
- // Platform-independent recursive file search
45
- const findMetadataFiles = ( ) => {
46
- const metadataFiles = [ ] ;
38
+ // Find all feature group directories in _tutorials
39
+ const findFeatureGroupDirectories = ( ) => {
40
+ const featureGroupDirs = [ ] ;
41
+
42
+ if ( ! fs . existsSync ( TUTORIALS_DIR ) ) {
43
+ console . warn ( `Tutorials directory does not exist: ${ TUTORIALS_DIR } ` ) ;
44
+ return featureGroupDirs ;
45
+ }
47
46
48
- const walkDir = ( dir ) => {
49
- if ( ! fs . existsSync ( dir ) ) {
50
- console . warn ( `Directory does not exist: ${ dir } ` ) ;
51
- return ;
52
- }
47
+ try {
48
+ const dirs = fs . readdirSync ( TUTORIALS_DIR , { withFileTypes : true } ) ;
53
49
54
- try {
55
- const files = fs . readdirSync ( dir ) ;
56
-
57
- files . forEach ( ( file ) => {
58
- const filePath = path . join ( dir , file ) ;
59
-
60
- try {
61
- const stat = fs . statSync ( filePath ) ;
62
-
63
- if ( stat . isDirectory ( ) ) {
64
- walkDir ( filePath ) ;
65
- } else if ( file === 'metadata.json' ) {
66
- metadataFiles . push ( filePath ) ;
67
- }
68
- } catch ( err ) {
69
- console . warn ( `Error accessing file ${ filePath } : ${ err . message } ` ) ;
70
- }
71
- } ) ;
72
- } catch ( err ) {
73
- console . warn ( `Error reading directory ${ dir } : ${ err . message } ` ) ;
74
- }
75
- } ;
50
+ dirs . forEach ( ( dirent ) => {
51
+ if ( dirent . isDirectory ( ) ) {
52
+ featureGroupDirs . push ( path . join ( TUTORIALS_DIR , dirent . name ) ) ;
53
+ }
54
+ } ) ;
55
+ } catch ( err ) {
56
+ console . warn ( `Error reading tutorials directory ${ TUTORIALS_DIR } : ${ err . message } ` ) ;
57
+ }
76
58
77
- walkDir ( PASSPORT_ROOT ) ;
78
- return metadataFiles ;
59
+ return featureGroupDirs ;
79
60
} ;
80
61
81
62
// Process metadata files
82
- const processMetadataFiles = ( metadataFiles ) => {
63
+ const processFeatureGroups = ( featureGroupDirs ) => {
83
64
const featuresObject = { } ;
84
65
85
- metadataFiles . forEach ( ( metadataFile ) => {
86
- console . log ( `Processing ${ metadataFile } ` ) ;
87
-
88
- // Extract feature directory
89
- const featureDir = path . dirname ( metadataFile ) ;
66
+ featureGroupDirs . forEach ( ( groupDir ) => {
67
+ const groupName = path . basename ( groupDir ) ;
68
+ console . log ( `Processing feature group: ${ groupName } ` ) ;
90
69
91
- // Get directory name as fallback feature name
92
- const dirName = path . basename ( featureDir ) ;
70
+ // Check if this group exists in features.json
71
+ if ( ! featureGroups [ groupName ] ) {
72
+ console . warn ( `Feature group ${ groupName } not found in features.json, skipping` ) ;
73
+ return ;
74
+ }
93
75
94
- // Try to find feature name in feature map, fallback to directory name
95
- let featureName = '' ;
96
- try {
97
- // Look for any script file in this directory
98
- const dirFiles = fs . readdirSync ( featureDir ) ;
99
- const scriptFiles = dirFiles . filter ( ( file ) => file . endsWith ( '.cs' ) ) ;
100
-
101
- // Try to match any script file to our feature map
102
- let found = false ;
103
- for ( const scriptFile of scriptFiles ) {
104
- if ( featuresMap [ scriptFile ] ) {
105
- featureName = featuresMap [ scriptFile ] ;
106
- found = true ;
107
- break ;
108
- }
109
- }
110
-
111
- if ( ! found ) {
112
- console . warn ( `No feature found in features.json for ${ featureDir } , using directory name` ) ;
113
- featureName = dirName ;
114
- }
115
- } catch ( error ) {
116
- console . warn ( `Error processing directory ${ featureDir } : ${ error . message } ` ) ;
117
- featureName = dirName ;
76
+ // Path to metadata.json in this feature group directory
77
+ const metadataPath = path . join ( groupDir , 'metadata.json' ) ;
78
+ if ( ! fs . existsSync ( metadataPath ) ) {
79
+ console . warn ( `No metadata.json found for feature group ${ groupName } in ${ groupDir } ` ) ;
80
+ return ;
118
81
}
119
82
120
- // Create feature key (kebab-case)
121
- const featureKey = featureName
83
+ // Path to tutorial.md in this feature group directory
84
+ const tutorialPath = path . join ( groupDir , 'tutorial.md' ) ;
85
+ const tutorialExists = fs . existsSync ( tutorialPath ) ;
86
+
87
+ // Create the feature key (kebab-case)
88
+ const featureKey = groupName
122
89
. replace ( / ( [ a - z ] ) ( [ A - Z ] ) / g, '$1-$2' )
123
90
. replace ( / \s + / g, '-' )
124
91
. replace ( / [ ^ a - z 0 - 9 - ] / gi, '' )
125
92
. toLowerCase ( ) ;
126
93
127
94
if ( ! featureKey ) {
128
- console . warn ( `Generated empty feature key for ${ featureDir } , skipping` ) ;
95
+ console . warn ( `Generated empty feature key for ${ groupName } , skipping` ) ;
129
96
return ;
130
97
}
131
98
132
- // Check for tutorial.md in the same directory
133
- const tutorialPath = path . join ( featureDir , 'tutorial.md' ) ;
134
- const tutorialExists = fs . existsSync ( tutorialPath ) ;
135
99
const tutorialFile = tutorialExists ? `${ featureKey } .md` : null ;
136
100
137
101
if ( ! tutorialExists ) {
138
- console . warn ( `No tutorial.md found for feature ${ featureName } in ${ featureDir } ` ) ;
102
+ console . warn ( `No tutorial.md found for feature group ${ groupName } in ${ groupDir } ` ) ;
139
103
}
140
104
141
105
// Read and process metadata
142
106
try {
143
- const metadataContent = fs . readFileSync ( metadataFile , 'utf8' ) ;
107
+ const metadataContent = fs . readFileSync ( metadataPath , 'utf8' ) ;
144
108
const metadata = JSON . parse ( metadataContent ) ;
145
109
146
110
// Add additional fields
147
- metadata . title = metadata . title || featureName ;
111
+ metadata . title = metadata . title || groupName ;
148
112
metadata . sidebar_order = metadata . sidebar_order || 0 ;
149
113
metadata . deprecated = metadata . deprecated || false ;
150
114
115
+ // Add feature group information
116
+ metadata . feature_group = groupName ;
117
+ metadata . features = Object . keys ( featureGroups [ groupName ] || { } ) ;
118
+
151
119
// Create the feature entry
152
120
featuresObject [ featureKey ] = {
153
121
tutorial : tutorialFile ,
154
122
metadata : metadata
155
123
} ;
156
124
} catch ( error ) {
157
- console . error ( `Error processing metadata file ${ metadataFile } : ${ error . message } ` ) ;
125
+ console . error ( `Error processing metadata file ${ metadataPath } : ${ error . message } ` ) ;
158
126
}
159
127
} ) ;
160
128
@@ -163,13 +131,13 @@ const processMetadataFiles = (metadataFiles) => {
163
131
164
132
try {
165
133
// Main execution
166
- const metadataFiles = findMetadataFiles ( ) ;
134
+ const featureGroupDirs = findFeatureGroupDirectories ( ) ;
167
135
168
- if ( metadataFiles . length === 0 ) {
169
- console . warn ( 'No metadata files found. Output file will be empty.' ) ;
136
+ if ( featureGroupDirs . length === 0 ) {
137
+ console . warn ( 'No feature group directories found. Output file will be empty.' ) ;
170
138
}
171
139
172
- const features = processMetadataFiles ( metadataFiles ) ;
140
+ const features = processFeatureGroups ( featureGroupDirs ) ;
173
141
174
142
// Create the final passport-features.json
175
143
fs . writeFileSync ( OUTPUT_FILE , JSON . stringify ( features , null , 2 ) ) ;
0 commit comments