Skip to content

Commit

Permalink
use the Fluent visitor to find syntax problems, see phetsims/joist#994
Browse files Browse the repository at this point in the history
  • Loading branch information
jessegreenberg committed Feb 5, 2025
1 parent 4a1af69 commit ebc912c
Showing 1 changed file with 28 additions and 4 deletions.
32 changes: 28 additions & 4 deletions js/browser-and-node/FluentLibrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ import { FluentParser } from '../../../sherpa/lib/fluent/fluent-syntax-0.19.0/sr
import { Visitor } from '../../../sherpa/lib/fluent/fluent-syntax-0.19.0/src/visitor.js';

/**
* A visitor that collects all term references in a Fluent AST.
* A visitor that collects Nodes from the AST so we can inspect them for problems.
*/
class TermCollector extends Visitor {
class FluentVisitor extends Visitor {
public readonly usedTerms = new Set<string>();
public readonly foundJunk = new Set<string>();

// IntentionalAny because the node type could not be found in Fluent source.
public override visitTermReference( node: IntentionalAny ): void {
Expand All @@ -33,6 +34,14 @@ class TermCollector extends Visitor {
// Continue traversing the AST
this.genericVisit( node );
}

// Nodes with syntax errors are called "junk" in Fluent and can be visited with this method.
public override visitJunk( node: IntentionalAny ): void {

this.foundJunk.add( node );

this.genericVisit( node );
}
}

class FluentLibrary {
Expand All @@ -57,6 +66,7 @@ class FluentLibrary {
* Verify syntax in the fluent file. Right now it checks for:
* - Message keys should use camelCase instead of dashes.
* - All terms used in the file should be defined.
* - All selectors must have a default case.
*/
public static verifyFluentFile( fluentFileString: string ): void {
const parser = new FluentParser();
Expand All @@ -75,8 +85,8 @@ class FluentLibrary {
.filter( entry => entry.type === 'Term' )
.map( entry => entry.id.name );

// Use the TermCollector to find all used terms.
const collector = new TermCollector();
// Use the FluentVisitor to find all used terms.
const collector = new FluentVisitor();
collector.visit( resource );

// Identify used terms that are not defined
Expand All @@ -88,6 +98,20 @@ class FluentLibrary {
const undefinedTermsFormatted = undefinedTerms.join( ', ' );
throw new Error( `These terms are not defined: [ ${undefinedTermsFormatted} ]` );
}

// Other problems found by the collector.
collector.foundJunk.forEach( ( junk: IntentionalAny ) => {

const messages = junk.annotations.map( ( annotation: IntentionalAny ) => annotation.message ).join( '\n' );

const errorReport = `Junk found in fluent file:
${messages}
${junk.content}
`;

throw new Error( errorReport );
} );
}
}

Expand Down

0 comments on commit ebc912c

Please sign in to comment.