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
 | |
| }
 |