Библиотеки договоров 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>`