UNPKG

llparse

Version:

[![Build Status](https://secure.travis-ci.org/indutny/llparse.svg)](http://travis-ci.org/indutny/llparse) [![NPM version](https://badge.fury.io/js/llparse.svg)](https://badge.fury.io/js/llparse)

123 lines (98 loc) 2.44 kB
'use strict'; const assert = require('assert'); class Node { constructor(type) { this.type = type; } } class Single extends Node { constructor() { super('single'); this.children = []; } } class Sequence extends Node { constructor(select) { super('sequence'); this.select = select; } } class Next extends Node { constructor(value, next) { super('next'); this.value = value === undefined ? null : value; this.next = next; } } class Trie { constructor(name) { this.name = name; } combine(cases) { const list = []; cases.forEach((one) => { one.linearize().forEach(item => list.push(item)); }); if (list.length === 0) return null; return this.level(list, []); } level(list, path) { list.sort((a, b) => { return a.key.compare(b.key); }); // TODO(indutny): validate non-empty keys const first = list[0].key; const last = list[list.length - 1].key; let common = 0; const min = Math.min(first.length, last.length); // Leaf if (min === 0) { assert.strictEqual(list.length, 1, `Duplicate entries in "${this.name}" at [ ${path.join(', ')} ]`); return new Next(list[0].value, list[0].next); } // Find the longest common sub-string for (; common < min; common++) if (first[common] !== last[common]) break; // Sequence if (common > 1) return this.sequence(list, first.slice(0, common), path); // Single return this.single(list, path); } slice(list, off) { return list.map((item) => { return { key: item.key.slice(off), next: item.next, value: item.value }; }); } sequence(list, prefix, path) { const res = new Sequence(prefix); const sliced = this.slice(list, prefix.length); res.children = this.level(sliced, path.concat(prefix)); return res; } single(list, path) { const keys = new Map(); for (let i = 0; i < list.length; i++) { const item = list[i]; const key = item.key[0]; if (keys.has(key)) keys.get(key).push(item); else keys.set(key, [ item ]); } const res = new Single(); keys.forEach((sublist, key) => { const sliced = this.slice(sublist, 1); res.children.push({ key, child: this.level(sliced, path.concat(key)) }); }); return res; } } module.exports = Trie;