1010 * governing permissions and limitations under the License.
1111 */
1212
13- import { isNonEmptyArray } from '@adobe/spacecat-shared-utils' ;
14-
1513import fs from 'fs' ;
1614import path from 'path' ;
15+ import { fileURLToPath } from 'url' ;
16+ import { isNonEmptyArray } from '@adobe/spacecat-shared-utils' ;
17+
1718import { say } from '../../utils/slack-utils.js' ;
1819
1920const TASK_TYPE = 'cwv-demo-suggestions-processor' ;
@@ -23,6 +24,35 @@ const INP = 'inp';
2324const DEMO = 'demo' ;
2425const MAX_CWV_DEMO_SUGGESTIONS = 2 ;
2526
27+ // Get the directory of the current module for resolving static files
28+ const filename = fileURLToPath ( import . meta. url ) ;
29+ const dirname = path . dirname ( filename ) ;
30+
31+ /**
32+ * Maps metric types to their corresponding markdown files
33+ */
34+ const METRIC_FILES = {
35+ lcp : [ 'lcp1.md' , 'lcp2.md' , 'lcp3.md' ] ,
36+ cls : [ 'cls1.md' , 'cls2.md' ] ,
37+ inp : [ 'inp1.md' ] ,
38+ } ;
39+
40+ /**
41+ * Reads content from a static markdown file
42+ * @param {string } fileName - The name of the file to read
43+ * @param {object } logger - The logger object for error logging
44+ * @returns {string|null } The file content or null if file doesn't exist
45+ */
46+ function readStaticFile ( fileName , logger ) {
47+ try {
48+ const filePath = path . resolve ( dirname , '../../static' , fileName ) ;
49+ return fs . readFileSync ( filePath , 'utf8' ) ;
50+ } catch ( error ) {
51+ logger . error ( `Failed to read static file ${ fileName } :` , error . message ) ;
52+ return null ;
53+ }
54+ }
55+
2656/**
2757 * CWV thresholds for determining if metrics have issues
2858 */
@@ -66,46 +96,61 @@ function hasExistingIssues(suggestion) {
6696}
6797
6898/**
69- * Reads content from a static file
70- * @param {string } fileName - The filename to read
71- * @param {object } logger - The logger object
72- * @returns {string|null } The file content or null if error
73- */
74- function readStaticFile ( fileName , logger ) {
75- try {
76- const filePath = path . resolve ( process . cwd ( ) , 'src/static' , fileName ) ;
77- const content = fs . readFileSync ( filePath , 'utf-8' ) ;
78- logger . debug ( `Successfully read content from ${ fileName } at ${ filePath } ` ) ;
79- return content ;
80- } catch ( error ) {
81- logger . error ( `Error reading static file ${ fileName } : ${ error . message } ` ) ;
82- return null ;
83- }
84- }
85-
86- /**
87- * Gets a random suggestion from the available suggestions for a given issue type
99+ * Gets a random suggestion from markdown files for the given issue type
88100 * @param {string } issueType - The type of issue (lcp, cls, inp)
89- * @param {object } logger - The logger object
101+ * @param {object } logger - The logger object for error logging
90102 * @returns {string|null } A random suggestion or null if none available
91103 */
92- function getRandomSuggestion ( issueType , cwvReferenceSuggestions , logger ) {
93- const suggestions = cwvReferenceSuggestions [ issueType ] ;
94- if ( ! isNonEmptyArray ( suggestions ) ) {
104+ function getRandomSuggestion ( issueType , logger ) {
105+ const files = METRIC_FILES [ issueType ] ;
106+ if ( ! isNonEmptyArray ( files ) ) {
95107 return null ;
96108 }
97109
98- const randomIndex = Math . floor ( Math . random ( ) * suggestions . length ) ;
99- const fileName = suggestions [ randomIndex ] ;
100-
101- // Read content from the referenced file
110+ const randomIndex = Math . floor ( Math . random ( ) * files . length ) ;
111+ const fileName = files [ randomIndex ] ;
102112 const content = readStaticFile ( fileName , logger ) ;
113+
103114 if ( ! content ) {
104- logger . error ( `Failed to read content from ${ fileName } ` ) ;
105115 return null ;
106116 }
107117
108- return content ;
118+ // Extract the main suggestion from the markdown content
119+ // Look for the Description section and extract its content
120+ const lines = content . split ( '\n' ) . map ( ( line ) => line . trim ( ) ) . filter ( ( line ) => line ) ;
121+
122+ let inDescriptionSection = false ;
123+ const descriptionLines = [ ] ;
124+
125+ for ( const line of lines ) {
126+ if ( line === '**Description**' ) {
127+ inDescriptionSection = true ;
128+ } else if ( inDescriptionSection ) {
129+ // Stop when we hit the next section (starts with **)
130+ if ( line . startsWith ( '**' ) && line !== '**Description**' ) {
131+ break ;
132+ }
133+ // Skip empty lines and code blocks
134+ if ( line && ! line . startsWith ( '```' ) ) {
135+ descriptionLines . push ( line ) ;
136+ }
137+ }
138+ }
139+
140+ // Return the first meaningful description line, or join multiple lines if needed
141+ if ( descriptionLines . length > 0 ) {
142+ return descriptionLines [ 0 ] ;
143+ }
144+
145+ // Fallback: look for any meaningful content after the title
146+ for ( let i = 1 ; i < lines . length ; i += 1 ) {
147+ const line = lines [ i ] ;
148+ if ( line && ! line . startsWith ( '#' ) && ! line . startsWith ( '**' ) && ! line . startsWith ( '-' ) && ! line . startsWith ( '```' ) ) {
149+ return line ;
150+ }
151+ }
152+
153+ return null ;
109154}
110155
111156/**
@@ -126,28 +171,18 @@ async function updateSuggestionWithGenericIssues(
126171) {
127172 let issuesAdded = 0 ;
128173
129- let cwvReferenceSuggestions = { lcp : [ ] , cls : [ ] , inp : [ ] } ;
130174 try {
131- const jsonPath = path . resolve ( process . cwd ( ) , 'src/static/aem-best-practices.json' ) ;
132- logger . info ( `Loading CWV reference suggestions from: ${ jsonPath } ` ) ;
133- const rawData = fs . readFileSync ( jsonPath , 'utf-8' ) ;
134- cwvReferenceSuggestions = JSON . parse ( rawData ) ;
135- await say ( env , logger , slackContext , `Loaded CWV reference suggestions from: ${ jsonPath } ` ) ;
136- } catch ( error ) {
137- logger . error ( `Error loading CWV reference suggestions: ${ error . message } ` ) ;
138- await say ( env , logger , slackContext , `Failed to load CWV reference suggestions: ${ error . message } ` ) ;
139- return 0 ;
140- }
175+ logger . info ( 'Loading CWV suggestions from markdown files' ) ;
176+ await say ( env , logger , slackContext , 'Loaded CWV suggestions from markdown files' ) ;
141177
142- try {
143178 const data = suggestion . getData ( ) ;
144179
145180 if ( ! data . issues ) {
146181 data . issues = [ ] ;
147182 }
148183
149184 for ( const issueType of metricIssues ) {
150- const randomSuggestion = getRandomSuggestion ( issueType , cwvReferenceSuggestions , logger ) ;
185+ const randomSuggestion = getRandomSuggestion ( issueType , logger ) ;
151186 if ( randomSuggestion ) {
152187 const genericIssue = {
153188 type : issueType ,
0 commit comments