You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
2.6 KiB
98 lines
2.6 KiB
import { tokenize, Delim, WhiteSpace } from '../tokenizer/index.js'; |
|
import { generateSourceMap } from './sourceMap.js'; |
|
import * as tokenBefore from './token-before.js'; |
|
|
|
const REVERSESOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\) |
|
|
|
function processChildren(node, delimeter) { |
|
if (typeof delimeter === 'function') { |
|
let prev = null; |
|
|
|
node.children.forEach(node => { |
|
if (prev !== null) { |
|
delimeter.call(this, prev); |
|
} |
|
|
|
this.node(node); |
|
prev = node; |
|
}); |
|
|
|
return; |
|
} |
|
|
|
node.children.forEach(this.node, this); |
|
} |
|
|
|
function processChunk(chunk) { |
|
tokenize(chunk, (type, start, end) => { |
|
this.token(type, chunk.slice(start, end)); |
|
}); |
|
} |
|
|
|
export function createGenerator(config) { |
|
const types = new Map(); |
|
|
|
for (let name in config.node) { |
|
const item = config.node[name]; |
|
const fn = item.generate || item; |
|
|
|
if (typeof fn === 'function') { |
|
types.set(name, item.generate || item); |
|
} |
|
} |
|
|
|
return function(node, options) { |
|
let buffer = ''; |
|
let prevCode = 0; |
|
let handlers = { |
|
node(node) { |
|
if (types.has(node.type)) { |
|
types.get(node.type).call(publicApi, node); |
|
} else { |
|
throw new Error('Unknown node type: ' + node.type); |
|
} |
|
}, |
|
tokenBefore: tokenBefore.safe, |
|
token(type, value) { |
|
prevCode = this.tokenBefore(prevCode, type, value); |
|
|
|
this.emit(value, type, false); |
|
|
|
if (type === Delim && value.charCodeAt(0) === REVERSESOLIDUS) { |
|
this.emit('\n', WhiteSpace, true); |
|
} |
|
}, |
|
emit(value) { |
|
buffer += value; |
|
}, |
|
result() { |
|
return buffer; |
|
} |
|
}; |
|
|
|
if (options) { |
|
if (typeof options.decorator === 'function') { |
|
handlers = options.decorator(handlers); |
|
} |
|
|
|
if (options.sourceMap) { |
|
handlers = generateSourceMap(handlers); |
|
} |
|
|
|
if (options.mode in tokenBefore) { |
|
handlers.tokenBefore = tokenBefore[options.mode]; |
|
} |
|
} |
|
|
|
const publicApi = { |
|
node: (node) => handlers.node(node), |
|
children: processChildren, |
|
token: (type, value) => handlers.token(type, value), |
|
tokenize: processChunk |
|
}; |
|
|
|
handlers.node(node); |
|
|
|
return handlers.result(); |
|
}; |
|
};
|
|
|