Библиотеки договоров JavaScript Code?
Я только начинаю новое веб-приложение, и я хочу реализовать некоторую форму проверки стиля контракта в моем JavaScript. Я сделал быстрый поиск в Google и наткнулся на JsContact, но синтаксис не совсем то, что я имел в виду. Кто-нибудь знает о других библиотеках?
Я думаю, что я хочу, чтобы синтаксис был чем-то вроде
String.prototype.padLeft = function(c, width) {
Verify.value(c).isRequired().isNotNull().isChar();
Verify.value(width).isRequired().isNotNull().isNumber().greaterThan(0);
...
Verify.value(result).isNotNull();
return result;
};
Хотя мне не понадобится много времени, чтобы собрать свою собственную библиотеку с синтаксисом/методами, которые я хочу, если кто-то еще уже выполнил эту работу, и она достаточно близко, это сэкономит мне некоторое время. Спасибо заранее.
UPDATE
У меня не будет времени, чтобы поработать над этим до сегодняшнего дня, поэтому я дам ему еще несколько часов, чтобы узнать, есть ли у кого-либо рекомендации. Если нет, я отправлю все, что я создаю где-то в качестве ответа ниже, чтобы другие люди могли ссылаться, если они пожелают.
Я также немного поразмыслил с API, который будет иметь смысл, и я сейчас думаю что-то вроде (надуманные примеры):
function searchUser(firstName, middleInit, lastName) {
Verify.value(firstName).isString().matching(/\w+/); // Must have value
Verify.value(middleInit).whenNotNull().isChar(); // May be null, but not undefined
Verify.value(lastName).isString().withMinimumLengthOf(2); // Must have value
...
}
function syncTime(serverTime, now) {
Verify.value(serverTime).isDate(); // Must have value.
Verify.value(now).whenDefined().isDate(); // May be undefined, but not null.
}
Моя текущая мысль заключается в том, что перенос значений NULL или UNDEFINED является нетипичным (по крайней мере для меня?), как таковым, а не явно указывая, что значение .isNotNull() вы фактически отключили бы правило для .whenDefined() или .whenNotNull(), как показано выше. Я могу сделать .whenNotNull() не ошибка на UNDEFINED, но я вижу NULL vs. UNDEFINED как важное различие; мы увидим... все другие методы будут довольно типичными... мыслями? комментарии?
Ответы
Ответ 1
Учитывая, что никто не рекомендовал никаких существующих библиотек, или что я сумасшедший, потому что думаю, что это хорошая идея, я пошел вперед и собрал базовую библиотеку. Код не причудливый, но он делает то, что я хочу, и он достаточно быстрый для запуска (приблизительно 40 прикованных проверок за мс в IE).
Я установил окончательный синтаксис, например:
function syncTime(serverTime, now) {
Verify.value(serverTime).always().isDate(); // Cannot be undefined or null.
Verify.value(now).whenDefined().isDate(); // Cannot be null, but must be date when defined.
//Code
}
function searchForUser(firstName, middleInit, lastName) {
Verify.value(firstName).always().isString().withMinimumLengthOf(2); // Cannot be undefined or null.
Verify.value(lastName).always().isString().withMinimumLengthOf(2); // Cannot be undefined or null.
Verify.value(middleInit).whenNotNull().isChar().between('A', 'Z'); // Cannot be undefined, but must be single char string when not null.
//Code
}
Я выбрал явное "Должен иметь ценность" с помощью проверки .always(), лично мне было приятно читать; но я видел, как кто-то идет другим путем.
Учитывая, что источник больше, чем я хочу опубликовать в этом ответе, пожалуйста, перейдите к этой странице CodePlex Wiki, если вы заинтересованы в источник. Думаю, это перешло к большей части свободной библиотеки утверждений; но он делает то, что мне нужно.
Обновление
Я обновил источник на связанной странице CodePlex выше. В частности, я изменил класс Verify, чтобы использовать "контекст значения", а не всегда создавать новые объекты Verifier; улучшена производительность IE (никогда не возникала проблема с FireFox или Chrome)... теперь обрабатывает около 100 целых чеков в мс в IE.
Ответ 2
Я могу предложить вам следующую библиотеку контрактов: dbc-code-contract.
NPM: https://www.npmjs.com/package/dbc-code-contracts
GitLab repo (home): https://gitlab.com/o.oleg/orbios.dbc#README
CI-сборки с модульными тестами: https://gitlab.com/o.oleg/orbios.dbc/-/jobs/
Пример кода:
Dbc.Contract.throwException = true;
const domId = "my-div";
const div = document.createElement("div");
div.id . = domId;
document.body.appendChild(div);
const state = Dbc.Dom.removeById(domId);
Dbc.Contract.isTrue(state);
Dbc.Contract.isNull(document.getElementById(domId));
Поддерживаются следующие контракты (2 ноября 2017 года):
- isFunction
- IsObject
- isSymbol
- isBoolean
- isTrue
- isFalse
- IsString
- isEmptyString
- isNotEmptyString
- areStringsEqual
- IsNumber
- isNumberLess
- isNumberBigger
- areNumbersEqual
- isValueNaN
- isDefined
- isUndefined
- IsNull
- IsArray
- isEmptyArray
- isNotEmptyArray
- isObjectImmutable
- isPromise
- isPrototypeOf
Кроме того, внутри DOM-методов из этой библиотеки есть внутренние проверки контрактов.
Ответ 3
Я также объединил свою идею контрактов типа, которая делает то, что я хочу. Немного поздно, я думаю, но я порекомендую его тем не менее для людей, желающих посмотреть на него: https://github.com/lindem/FirstContract
Это WIP, но мне нужно что-то вроде этого.
function bmi (weight, height) {
return weight / height * height;
}
var c = require("firstcontract").c
/*
* contract applies to function taking two non-negative numbers,
* returning a negative number:
*/
, contract = c(["R+0", "R+0"], "R+0")
, cbmi = contract(bmi)
;
он был создан так, чтобы я мог добавлять и удалять его, не меняя функцию, которая сама контролировала, и обеспечивает просто зажим вокруг функции. Это commonjs и на npm.
Ответ 4
Еще один - https://www.npmjs.com/package/bycontract
Это небольшая библиотека, которая ожидает выражения JSDoc (http://usejsdoc.org/) для контракта. Хороший шанс для вас уже знаком с синтаксисом.
Просто просмотрите его в действии:
// Simple test
byContract( true, "boolean" ); // ok
// Multiple Types
byContract( 100, "string|number|boolean" ); // ok
// Optional Parameters
function foo( bar, baz ) {
byContract( arguments, [ "number=", "string=" ] );
}
Вот пример реального мира:
/**
* @param {number|string} sum
* @param {Object.<string, string>} payload
* @param {function} cb
* @returns {HTMLElement}
*/
function foo( sum, payload, cb ) {
// Test if the contract is respected at entry point
byContract( arguments, [ "number|string", "Object.<string, string>", "function" ] );
// ..
var res = document.createElement( "div" );
// Test if the contract is respected at exit point
return byContract( res, HTMLElement );
}
// Test it
foo( 100, { foo: "foo" }, function(){}); // ok
foo( 100, { foo: 100 }, function(){}); // exception - ByContractError: Value of index 1 violates the contract `Object.<string, string>`