132 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			132 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | 'use strict' | ||
|  | 
 | ||
|  | var licenses = [] | ||
|  |   .concat(require('spdx-license-ids')) | ||
|  |   .concat(require('spdx-license-ids/deprecated')) | ||
|  | var exceptions = require('spdx-exceptions') | ||
|  | 
 | ||
|  | module.exports = function (source) { | ||
|  |   var index = 0 | ||
|  | 
 | ||
|  |   function hasMore () { | ||
|  |     return index < source.length | ||
|  |   } | ||
|  | 
 | ||
|  |   // `value` can be a regexp or a string.
 | ||
|  |   // If it is recognized, the matching source string is returned and
 | ||
|  |   // the index is incremented. Otherwise `undefined` is returned.
 | ||
|  |   function read (value) { | ||
|  |     if (value instanceof RegExp) { | ||
|  |       var chars = source.slice(index) | ||
|  |       var match = chars.match(value) | ||
|  |       if (match) { | ||
|  |         index += match[0].length | ||
|  |         return match[0] | ||
|  |       } | ||
|  |     } else { | ||
|  |       if (source.indexOf(value, index) === index) { | ||
|  |         index += value.length | ||
|  |         return value | ||
|  |       } | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   function skipWhitespace () { | ||
|  |     read(/[ ]*/) | ||
|  |   } | ||
|  | 
 | ||
|  |   function operator () { | ||
|  |     var string | ||
|  |     var possibilities = ['WITH', 'AND', 'OR', '(', ')', ':', '+'] | ||
|  |     for (var i = 0; i < possibilities.length; i++) { | ||
|  |       string = read(possibilities[i]) | ||
|  |       if (string) { | ||
|  |         break | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     if (string === '+' && index > 1 && source[index - 2] === ' ') { | ||
|  |       throw new Error('Space before `+`') | ||
|  |     } | ||
|  | 
 | ||
|  |     return string && { | ||
|  |       type: 'OPERATOR', | ||
|  |       string: string | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   function idstring () { | ||
|  |     return read(/[A-Za-z0-9-.]+/) | ||
|  |   } | ||
|  | 
 | ||
|  |   function expectIdstring () { | ||
|  |     var string = idstring() | ||
|  |     if (!string) { | ||
|  |       throw new Error('Expected idstring at offset ' + index) | ||
|  |     } | ||
|  |     return string | ||
|  |   } | ||
|  | 
 | ||
|  |   function documentRef () { | ||
|  |     if (read('DocumentRef-')) { | ||
|  |       var string = expectIdstring() | ||
|  |       return {type: 'DOCUMENTREF', string: string} | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   function licenseRef () { | ||
|  |     if (read('LicenseRef-')) { | ||
|  |       var string = expectIdstring() | ||
|  |       return {type: 'LICENSEREF', string: string} | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   function identifier () { | ||
|  |     var begin = index | ||
|  |     var string = idstring() | ||
|  | 
 | ||
|  |     if (licenses.indexOf(string) !== -1) { | ||
|  |       return { | ||
|  |         type: 'LICENSE', | ||
|  |         string: string | ||
|  |       } | ||
|  |     } else if (exceptions.indexOf(string) !== -1) { | ||
|  |       return { | ||
|  |         type: 'EXCEPTION', | ||
|  |         string: string | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     index = begin | ||
|  |   } | ||
|  | 
 | ||
|  |   // Tries to read the next token. Returns `undefined` if no token is
 | ||
|  |   // recognized.
 | ||
|  |   function parseToken () { | ||
|  |     // Ordering matters
 | ||
|  |     return ( | ||
|  |       operator() || | ||
|  |       documentRef() || | ||
|  |       licenseRef() || | ||
|  |       identifier() | ||
|  |     ) | ||
|  |   } | ||
|  | 
 | ||
|  |   var tokens = [] | ||
|  |   while (hasMore()) { | ||
|  |     skipWhitespace() | ||
|  |     if (!hasMore()) { | ||
|  |       break | ||
|  |     } | ||
|  | 
 | ||
|  |     var token = parseToken() | ||
|  |     if (!token) { | ||
|  |       throw new Error('Unexpected `' + source[index] + | ||
|  |                       '` at offset ' + index) | ||
|  |     } | ||
|  | 
 | ||
|  |     tokens.push(token) | ||
|  |   } | ||
|  |   return tokens | ||
|  | } |