nodejs-pkg-tools v0.4.1
🎲 JS pkg tools
Чтение, модификация и запись *.json
файлов.
npm i -D nodejs-pkg-tools
Что делает этот пакет:
- Чтение
package.json
или любого валидногоjson
. - Включение/исключение свойств.
- Переопределение свойств пользовательским модификатором.
- Использование шаблона
foo.*.bar
с модификатором для доступа к нескольким свойствам одного уровня. - Запись файла в установленный путь.
- Доступна обычная функция
modify({json: '...'}).toValue() -> {...}
без доступа к файловой системе. - Дополнительные функции очистки
clearDir(...)
и копирования каталогаcopyDir(...)
.
Использование
Скопируйте файл в другой каталог, изменив некоторые свойства и относительные пути всего уровня exports:{}
.
const nodeRoot = rwModify({
mode: 'over',
exclude: ['devDependencies', 'private'],
sample: {
'version': '0.8.5-alpha'
// Модифицируйте все пути одним выражением.
'exports.*.*': makeModifier((value, key, path) =>
[true, true, value.replace('dist/', '')])
}
}, './package.json', './dist/package.json')
- Было
{
"version": "0.8.4",
...
"devDependencies": { ... },
"private": true,
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}
- Стало
{
"version": "0.8.5-alpha",
...
"exports": {
".": {
"import": "./index.js",
"types": "./index.d.ts"
}
}
}
Обработка узлов
После создания дерева узлов(1), каждый node помечается флагом удалить/оставить, зависит от опции mode
.
При удалении(2), например узла A, флаг удаления распространяется вниз по дереву, но не удаляет узлы. Пока узел явно не переопределен его можно восстановить.
На следующем этапе(3) можно сохранить ранее удаленный узел, например B. Сохранение распространяется в обе стороны - вверх до корневого node и вниз по дочерним узлам.
Когда на результирующем объекте вызывается toValue()
или toJson()
, дерево собирается сверху, отбрасывая узлы отмеченные флагом remove.
🧹 Пустые
{}|[]
фильтруются и не включаются в результат. Вот такое{foo:{bar:{box:[]}}}
- преобразуется в такое{}
.
Опции и формат пути
Путь к свойствам описывается строкой с разделителем "."
. Звездочка "*"
определяет любое свойство в структуре или массиве. В TypeScript
путь имеет псевдоним type KeyPath = string
.
"foo.bar" <- Ok
"box.**" <- Bad - Двойные ".." и "**" недопустимы.
"over..tor" <- Bad
".game.oh." <- Bad - В начале и конце нельзя ".".
"well.be.*" <- Ok - Звездочки "*" можно.
"*.*.*.*.*" <- Ok 👀
Этот пакет имеет три основных функции:
import {
type IRootNode, ... несколько разных типов,
makeModifier, modify, rwModify
} from 'nodejs-pkg-tools'
// Модификатор используемый в параметре Options.sample.
const marker = makeModifier(boolean | Modifier): ModifierMarker
// Модификация Json-строки или валидной структуры {}|[].
const nodeRoot = modify(options: Options): IRootNode
// Чтение и запись файла.
const rwNodeRoot = rwModify (options: Options, src?: string, dest?: string): IRootNode
Options: {json?|value?, mode?, space?, include?, exclude?, sample?}
Объект опций.
Options.mode: 'strict'(default)|'over'|'error'|'strict_error'|'over_error'
От выбранного режима зависит установка флагов по умолчанию и действие при ошибках:
"strict"
(default) - Всем node устанавливается remove-флаг. Сохранить узел можно явной установкой пути вinclude
или в модификатореsample
."over"
- Поведение обратное"strict"
."error"
- Любая ошибка, например невалидное значение, предотвращает дальнейшую обработку. Результат будет иметьnodeRoot.isFatalError:true
. Ошибки не влияющие на результат, когда не существует путиexclude
, игнорируются.
Параметр mode
тестируется регулярным выражением и может быть установлен в любых вариациях, даже так error_2022_over
.
Ошибки разбора Json или чтения файла, всегда являются фатальными и не возвращают ожидаемый результат. Функции не выбрасывают исключений, проверять наличие ошибок следует через интерфейс IRootNode
. В случае isFatalError
, текущий результат будет потерен и toJson()
или toValue()
, будут возвращать ""
или null
.
📌 Не устанавливайте
error
при преобразованииJS
-объекта, где могут бытьfunction
,undefined
иsymbol
. В этом случае невалидные значения игнорируются и ошибка не устанавливается, в том числе и для ошибок поиска путей. Список всех ошибок всегда доступен черезIRootNode.errors:IErrors
.
Больше информации в файле src/errors.ts.
Options.space: number>=0
(default: 2)
Это значение будет передано в JSON.stringify(value, null, space)
.
Options.json?: string
| Options.value?: JsonPrimitive|[]|{}
Строка Json или валидное значение. Объект содержащий function|Symbol|BigInt|undefined
недопустим и вызовет ошибку, если установлено mode:'error'
.
rwModify(opts, src?, dest?)
можно использовать с любым вариантом источника данных в порядке приоритета src? || json? || value
.
Options.include: KeyPath[]
Массив путей для включения. Этот массив устанавливает флаг сохранитьсвойство_ в первую очередь.
Options.exclude: KeyPath[]
Применяется после Options.include
.
Options.sample: {...}|[...][]
{[k in KeyPath]: ValidValue | ModifierMarker}
[KeyPath, ...][]
[string[], ...][]
Объект или массив позволяющий удалять/модифицировать/устанавливать новые свойства и их значения. В отличие от include/exclude
, здесь нет определенного порядка действий. Свойства можно удалить, добавить, изменить и снова удалить.
import { type Sample, makeModifier, modify, rwModify } from 'nodejs-pkg-tools'
const sample: Sample = {
// Отметим весь узел для удаления...
"your.very": makeModifier(false),
// ... и оставим вложенный узел - он все еще существует.
"your.very.long": makeModifier(true)
// Независимо от наличия свойства в целевом объекте,
// оно будет создано. Глубина не имеет значение.
// Путем всегда является ключ, а значением {foo: "bar"}.
"your.very.long.path": {foo: "bar"},
// Определять путь в виде вложенных структур нельзя.
// Неясно: путь это или значение {very:...}.
your: {very: {long: { path: {foo: "bar"}}}}
}
Несмотря на удобный формат {key: value}
, объекты, имеющие целочисленные ключи, самовольно распоряжаются сортировкой. Точный порядок обработки можно определить массивом записей.
// Такое определение ...
const sample: Sample = [
["your.path.*", makeModifier((value, key, path) => {...})],
["engines.node", "^18.7.0"]
]
// ... эквивалентно
const sample: Sample = {
"your.path.*": makeModifier((value, key, path) => {...}),
"engines.node": "^18.7.0"
}
Формат определения KeyPath
не позволяет указать точки "."
и звездочки "*"
. Такие ключи передаются массивом.
const sample: Sample = [
[["exports", "."], "newValue"],
// Массив пути не обрабатывается и используется как есть.
[["description", "bar**..box", "repo", ""], makeModifier(true)]
// Имя свойства ->^^^^^^^^^^ ^^<- и это имя
]
Смешивать различные варианты Sample
не допускается.
Modifier(value, key, []): boolean | [boolean, boolean, (Primitive|[]|{})]
Пользовательский обработчик принимает три аргумента:
value: (Primitive|[]|{})
- Значение запрашиваемого свойства.key: (null|string|number)
- Ключ илиnull
, если это корень. Последний элемент в массивеpath
.path: (string|number)[]
- Путь от корня или пустой массив.
Функция должна возвратить один из вариантов:
boolean
:true
- Игнорировать, свойство может быть удалено или сохранено в зависимости от текущих установок.false
- Прервать обработку и установить фатальную ошибку.
[boolean, boolean, (Primitive|[]|{})]
:[0]!
- Еслиfalse
свойство будет удалено, при этом остальные элементы игнорируются. Приtrue
оценивается элемент[1]
и свойству устанавливается флаг сохранения.[1]?
- Действие. Приtrue
обновляем значение из[2]
, иначе оставляем оригинал.[2]?
- Любое валидное значения для переопределения текущего свойства, должно быть установлено если[0]:true
и[1]:true
.
📌 Обработчик должен устанавливаться через
makeModifier()
. Любое другой тип оценивается как значение для переопределения свойства.
Этот файл 📄 содержит все доступные интерфейсы с комментариями.