1- import { VersionExpressionSets } from '@nomicfoundation/slang/ast' ;
21import { NonterminalKind , Query } from '@nomicfoundation/slang/cst' ;
32import { Parser } from '@nomicfoundation/slang/parser' ;
43import strip from 'strip-comments' ;
76 minSatisfying ,
87 minor ,
98 major ,
10- minVersion ,
9+ satisfies ,
1110 validRange
1211} from 'semver' ;
1312
@@ -26,30 +25,39 @@ const milestoneVersions = Array.from(
2625 return versions ;
2726 } , [ ] ) ;
2827
29- export function inferLanguage ( text : string ) : Parser {
30- let inferredRange = '' ;
28+ // TODO if we ended up selecting the same version that the pragmas were parsed with,
29+ // should we be able to reuse/just return the already parsed CST, instead of
30+ // returning a Parser and forcing user to parse it again?
31+ export function createParser ( text : string ) : Parser {
32+ let inferredRanges : string [ ] = [ ] ;
3133
3234 for ( const version of milestoneVersions ) {
3335 try {
34- inferredRange = tryToCollectPragmas ( text , version ) ;
36+ inferredRanges = tryToCollectPragmas ( text , version ) ;
3537 break ;
3638 } catch { }
3739 }
3840
39- if ( ! minVersion ( inferredRange ) ) {
40- throw new Error (
41- "Couldn't infer any version from the ranges in the pragmas."
42- ) ;
43- }
44-
45- const maxSatisfyingVersion = maxSatisfying ( supportedVersions , inferredRange ) ;
41+ const satisfyingVersions = inferredRanges . reduce (
42+ ( versions , inferredRange ) => {
43+ if ( ! validRange ( inferredRange ) ) {
44+ throw new Error (
45+ "Couldn't infer any version from the ranges in the pragmas."
46+ ) ;
47+ }
48+ return versions . filter ( ( supportedVersion ) =>
49+ satisfies ( supportedVersion , inferredRange )
50+ ) ;
51+ } ,
52+ supportedVersions
53+ ) ;
4654
47- return maxSatisfyingVersion
48- ? Parser . create ( maxSatisfyingVersion )
55+ return satisfyingVersions . length > 0
56+ ? Parser . create ( satisfyingVersions [ satisfyingVersions . length - 1 ] )
4957 : Parser . create ( supportedVersions [ supportedVersions . length - 1 ] ) ;
5058}
5159
52- function tryToCollectPragmas ( text : string , version : string ) : string {
60+ function tryToCollectPragmas ( text : string , version : string ) : string [ ] {
5361 const language = Parser . create ( version ) ;
5462 const parseOutput = language . parse ( NonterminalKind . SourceUnit , text ) ;
5563 const query = Query . parse (
@@ -61,29 +69,22 @@ function tryToCollectPragmas(text: string, version: string): string {
6169 let match ;
6270 while ( ( match = matches . next ( ) ) ) {
6371 ranges . push (
64- strip (
65- new VersionExpressionSets (
66- match . captures . versionRanges [ 0 ] . node . asNonterminalNode ( ) !
67- ) . cst . unparse ( ) ,
68- { keepProtected : true }
69- )
72+ strip ( match . captures . versionRanges [ 0 ] . node . unparse ( ) , {
73+ keepProtected : true
74+ } )
7075 ) ;
7176 }
7277
73- // Check if we found pragmas.
7478 if ( ranges . length === 0 ) {
7579 // If we didn't find pragmas but succeeded parsing the source we keep it.
7680 if ( parseOutput . isValid ( ) ) {
77- return version ;
81+ return [ version ] ;
7882 }
7983 // Otherwise we throw.
8084 throw new Error (
8185 `Using version ${ version } did not find any pragma statement and does not parse without errors.`
8286 ) ;
8387 }
8488
85- // validRange rewrites `0.5.0 - 0.6.0` as `>=0.5.0 <=0.6.0` but it returns
86- // null if the range is not valid. We have to coerce null to 'null' so it
87- // fails the `minVersion(inferredRange)` call.
88- return ranges . map ( ( range ) => `${ validRange ( range ) } ` ) . join ( ' ' ) ;
89+ return ranges ;
8990}
0 commit comments