npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nut-parser

v1.0.9

Published

Инструмент для парсинга различных грамматик.

Downloads

7

Readme

nut-parser

Установка

npm install nut-parser

Использование

Подключение

let {Lexer, Parser} = require('nut-parser');

Принцип работы лексера

Лексер перебирает символы из входной строки, и для каждого символа поочерёдно применяет все добавленные правила (о добавлении правил - ниже). Если символ соответствует правилу - правило сохраняется, если нет - правило отбрасывается и не применяется для следующих символов. Как только список применяемых правил окажется пуст, лексер вернётся на один символ назад. Затем добавит в результирующий массив лексему с именем последнего актуального правила и контентом - строкой от начала разбора и до текущей позиции. Дальнейший разбор продолжится с текущей позиции с применением всех правил.

Для примера разберём строку "43.3 ы", c применением 2х правил. Первое правило для пробелов (любое количество подряд):

function(char, state){
	if(state === 1 && char === ' ') return 1;
	return 0;
};

Второе правило для чисел (С точкой или без):

function(char, state){
	if(state === 1 && /[0-9]/.test(char)) return 2;
	if(state === 2 && /[0-9]/.test(char)) {
		if(/[0-9]/.test(char)) return 2;
		if(/[.]/.test(char)) return -3;
	}
	if(state === -3 && /[0-9]/.test(char)) return 2;
	return 0;
};

Первый символ, который поступает в лексер - "4". В это время state (состояние) всех правил равно 1. Первое правило получает char = "4" state = 1 и возвращает 0 (поэтому для последующих символов это правило применяться не будет. Т.е. данная лексема уже точно не пробел). Второе правило получает char = "4" state = 1 и возвращает 2.

Далее лексер проверит второй символ - "3". Первое правило проверяться не будет, так как ранее функция вернула 0. Второе правило получит char = "3" state = 2 (на прошлом символе функция вернула состояние 2).

Далее третий символ - ".". Первая функция по-прежнему не применяется. А вторая применяется с аргументами char = "." state = 2, и возвращает -3 (отрицательное число означает, что для следующих символов это правило применяться будет, но в качестве конечного символа не рассматривается. В данном случае это признак того, что число не может заканчиваться точкой).

Четвёртый символ - "3". Второе правило примет char = "3" state = -3, вернёт 2.

Следующий символ " ". Первое правило по-прежнему не работает. Второе примет char = " " state = 2, и вернёт 0. На этом этапе у нас нет работающих правил (все вернули 0), поэтому лексер вернётся на один символ назад и создаст лексему из единственного работающего правила для этого символа (символ "3", второе правило). В результирующий массив будет записана лексема:

{name: "имя правила для чисел", content: "43.3", begin: 0, end: 4}, begin и end - позиция лексемы в исходной строке.

Далее лексер будет рассматривать остаток строки - " ы". Все правила снова получат состояние 1. Первый символ - " ". Первое правило получает char = " " state = 1 и возвращает 1. Второе правило получает char = " " state = 1 и возвращает 0. Для второго символа "ы" теперь актуально только первое правило, которое получает char = "ы" state = 1 и возвращает 0. Теперь актуальных правил нет, лексер возвращается на один символ назад и добавляет лексему в результирующий массив:

{name: "имя правила для пробелов", content: " ", begin: 4, end: 5}

Далее лексер рассмотрит остаток строки - "ы". Оба правила вернут 0 для первого символа, и лексер создаст лексему из этого символа с именем "unknown".

Задание правил для лексера

Задание правил, по которым будут создаваться лексемы происходит через метод лексера addRule объекта Lexer.

Lexer.addRule(lang, name, cb)
  • lang(строка) - язык для которого будет действовать правило;
  • name(строка) - имя правила. Будет помещено в лексему в свойство name;
  • cb - Функция обработки одного символа (подробно рассмотрена в предыдущем разделе), принимает два параметра char - текущий (проверяемый) символ, state - состояние, которое функция вернула в прошлый раз (для первого символа - 1). Возвращает новое состояние (0 - символ не соответствует правилам; отрицательное число - символ соответствует правилу, но не может быть последним; положительное число - символ соответствует правилу).

Пример для десятичных целых чисел языка JavaScript:

Lexer.addRule('js', 'number', function(char, state){
	if(state === 1 && /[0-9]/.test(char)) return 1;
	return 0;
});

Запуск лексера

let lexemes = Lexer.run(text, lang);
  • text(строка) - текст, который нужно распарсить
  • lang(строка) - язык текста. Из тех языков, которые добавлялись для лексера через метод addRule.

В lexemes попадёт массив лексем, который можно передать парсеру, или false, если нет правил разбора для данного языка.

Задание правил для парсера

Задание правил, по которым будет осуществляться разбор лексем происходит через метод лексера addRule объекта Parser.

Parser.addRule(lang, state, cb)
  • lang(строка) - язык для которого будет действовать правило;
  • state(строка) - текущее состояние парсера;
  • cb - Функция обработки лексемы, принимает два параметра lex - текущая лексема, memory - глобальный объект который вернёт парсер после окончания работы. Возврашает имя нового состояния, или объект со свойством parseError - если имеет место синтаксическая ошибка (в таком случае парсер завершит свою работу и вернёт этот объект, добавив в него информацию о лексеме в свойство errorLexeme).

Запуск парсера

let result = Parser.run(lexemes, lang);
  • lexemes(массив) - лексемы полученные от лексера
  • lang(строка) - язык парсинга. Из тех языков, которые добавлялись для парсера через метод addRule.

В result попадёт объект memory, который модифицировался через addRule, или объект ошибки со свойством parseError.

Проекты на основе nut-parser