Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature work 0406 #8

Merged
merged 11 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
# misc
~*
*.backup
*.tgz

npm-debug.log*


.nx/cache
36 changes: 20 additions & 16 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
/packages/*/tests
/packages/*/src
/coverage
/docs
/node_modules
/typedoc
/typedoc_output
/.github
/.vscode
tsconfig.json
.eslintignore
.gitattributes
.gitignore
eslintrc.json
packages-lock.json
typedoc.json
tests/
/src/
coverage/
docs/
node_modules/
typedoc/
typedoc_output/
tsconfig*.json
typedoc.json
gulpfile.js
gulpfile.mjs
README.md.backup
jest.config.*
# .eslintignore
# .gitattributes
# .gitignore
# eslintrc.json
# packages-lock.json
# .github/
# .vscode/
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## 0.9.5
!!!PENDING
32 changes: 23 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ supporting libraries (pending) are well-informed on those matters.
- Comparer customization: Supports Conditions that compare two values so they can handler your non-standard data types.

# Learning Jivs
[Jivs source code](https://github.com/plblum/jivs) is heavily and meaningfully commented, and its all available in TypeDoc format at [jivs.peterblum.com/typedoc](http://jivs.peterblum.com/typedoc). Use this section for an orientation.
[Jivs source code](https://github.com/plblum/jivs) is heavily and meaningfully commented, and it is all available in TypeDoc format at [jivs.peterblum.com/typedoc](http://jivs.peterblum.com/typedoc). Use this section for an orientation.

## Quick terminology overview
Here are a few terms used.
Expand Down Expand Up @@ -134,7 +134,7 @@ You will be working with classes and interfaces. Here are the primary pieces to

- `InputValidator class` -- Handle the validation process of a single rule and deliver a list of issues found to the ValidationManager, where your UI elements can consume it.

- `ValidationServices class`-- Provides a variety of services and factories to all of the above classes. This is where much of customization occurs. Here are several interfaces supported by ValidationServices which empower Jivs.
- `ValidationServices class`-- Provides dependency injection and configuration through a variety of services and factories. This is where much of customization occurs. Here are several interfaces supported by ValidationServices which empower Jivs.
- `IDataTypeFormatter` -- Provides localized strings for the tokens within error messages. For example, if validating a date against a range, your error message may look like this: "The value must be between {Minimum} and {Maximum}." With a Date-oriented DataTypeFormatter (supplied), those tokens will appear as localized date strings.
- `IDataTypeConverter` -- For these use cases:
+ Changing an object value into something as simple as a string or number for Conditions that compare values. The JavaScript Date object is a good example, as you should use its getTime() function for comparisons.
Expand Down Expand Up @@ -188,7 +188,7 @@ Jivs provides numerous `Condition classes`.
<details>
<summary>Expand to see just a few.</summary>

- `RequiredTextCondition`, `RequiredIndexCondition` - for required fields
- `RequiredTextCondition`, `StringNotEmptyCondition`, `NotNullCondition` - for required fields
- `DataTypeCheckCondition`, `RegExpCondition` - for checking the data conforms to the data type.
- `RangeCondition`, `EqualToCondition`, `GreaterThanCondition` - Comparing values
- `AllMatchCondition`, `AnyMatchCondition` - For creating complex logic by using multiple `Conditions`.
Expand Down Expand Up @@ -248,7 +248,6 @@ class Factory
}
}
```
Use your Factory as you assemble the `ValidationManagerConfig object`. Its just one part of the work to configure the `ValidationManager`.

## ValueHosts and their IDs

Expand All @@ -261,7 +260,22 @@ In this example, our Model’s property names are used in the input tag’s name
| FirstName | `<input type="text" name="FirstName" />`
| LastName | `<input type="text" name="LastName" />`

Jivs wants those same names for basically the same purpose of correlating with fields in the Model. Instead of an HTML tag, Jivs uses the `ValueHost class`.
Jivs wants those same names for basically the same purpose of correlating with fields in the Model. Instead of an HTML tag, Jivs uses classes that implement the `IValueHost interface`.
```ts
interface IValueHost {
getId(): string;
getDataType(): null | string;
getLabel(): string;
setLabel(label, labell10n?): void;
getValue(): any;
setValue(value, options?): void;
setValueToUndefined(options?): void;

isChanged: boolean;
saveIntoState(key, value): void;
getFromState(key): undefined | ValidTypesForStateStorage;
}
```
When we configure the above Model for Jivs, you can imagine something like this object:
```ts
[
Expand Down Expand Up @@ -345,13 +359,13 @@ Because this is so full of goodness, let’s go through each property.
- `conditionDescriptor` – Already described above. It is not the only way to setup a Condition…
- `conditionCreator` – Alternative to creating a Condition by returning an implementation of ICondition. This choice gives you a lot of flexibility, especially when you have some complex logic that you feel you can code up in an evaluate method easier than using a bunch of Conditions.
- `errorMessage` – A template for the message reporting an issue. Its intended location is nearby the Input, such that you can omit including the field’s label. “This field requires a value”. As a template, it provides tokens which can be replaced by live data. (Discussed later).
- `summaryMessage` – Same idea as errorMessage except to be shown in a Validation Summary. Its normal to include the field label in this message, using the {Label} token: “{Label} requires a value”.
- `summaryMessage` – Same idea as errorMessage except to be shown in a Validation Summary. It's normal to include the field label in this message, using the {Label} token: “{Label} requires a value”.
- `severity` – Controls some validation behaviors with these three values.
- `Error` – normal error and the default when this field is omitted.
- `Severe` – If there are more validation rules, skip them. Severity=Error continues to evaluate the remaining validation rules.
- `Warning` – Want to give the user some direction, but not prevent saving the data.
- `enabled` – A way to quickly disable the InputValidator.
- `enablerDescriptor` and `EnablerCreator` – The *Enabler* uses a `Condition` to determine if the `InputValidator` can validate. Often validation rules depend on other information for that. For example, you have a checkbox associated with a text box. Any validation rule on the text box isn’t used unless the checkbox is marked. You would assign a `Condition` to evaluate the value of the checkbox to the Enabler.
- `enablerDescriptor` and `EnablerCreator` – The *Enabler* uses a `Condition` to determine if the `InputValidator` is enabled. Often validation rules depend on other information for that. For example, you have a checkbox associated with a text box. Any validation rule on the text box isn’t used unless the checkbox is marked. You would assign a `Condition` to evaluate the value of the checkbox to the Enabler.

Now let’s place the `InputValidatorDescriptor` into our previous example using a Model with FirstName and LastName.
```ts
Expand Down Expand Up @@ -431,7 +445,7 @@ Let’s go through this type.

- `services` – Always takes a `ValidationServices object`, which is rich with services for dependency injection and factories. You will need to do a bunch to configure this, but don’t worry, we’ve got a code snippet to inject into your app to assist. (Described later.)
- `valueHostDescriptors` – Already previously described. However, we haven’t mentioned including `NonInputValueHost classes` for data that isn’t associated with an Input field. `ValueHosts` expose values to validation, and some of those values may not come from editable elements. One use-case is taking value from a property on the Model that is used for comparisons. There are several other use-cases described later.
- `savedState` and `SavedValueHostStates` – `ValidationManager` is stateless, or at least it knows how to offload its stateful data to the application. If you want to retain state, you’ll capture the latest states using the `OnStateChanged` and `OnValueHostStateChanged` events, and pass the values back into these two Config properties.
- `savedState` and `SavedValueHostStates` – `ValidationManager` knows how to offload its stateful data to the application. If you want to retain state, you’ll capture the latest states using the `OnStateChanged` and `OnValueHostStateChanged` events, and pass the values back into these two Config properties when you recreate it.
- `onStateChanged` and `onValueHostStateChanged` must be setup if you maintain the states. They supply a copy of the states for you to save.
- `onValueChanged` notifies you when a `ValueHost` had its value changed.
- `onInputValueChanged` notifies you when an `InputValueHost` had its Input Value changed.
Expand All @@ -440,7 +454,7 @@ Let’s go through this type.
## Configuring the ValidationServices
The `ValidationServices class` supports the operations of Validation with services and factories, which of course means you can heavily customize Jivs through the power of interfaces and dependency injection.

`ValidationServices` is where we register new `Conditions` and classes to help work with all of the data types you might have in your Model. None of those classes are prepopulated. So let’s get them setup.
`ValidationServices` is where we register new `Conditions` and classes to help work with all of the data types you might have in your Model. None of those classes are prepopulated (so that you are not stuck with classes that you won't use). So let’s get them setup.

Go to [https://github.com/plblum/jivs/blob/main/starter_code/create_services.ts](https://github.com/plblum/jivs/blob/main/starter_code/create_services.ts)

Expand Down
11 changes: 9 additions & 2 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ gulp.task('clean', function () {
'starter_code/build/**',
'packages/**/build/**/*',
'packages/**/src/**/*.d.ts',
// 'packages/**/src/**/*.js',
'packages/**/src/**/*.map'
'packages/*/*.d.ts',
'packages/**/src/**/*.js',
'packages/**/src/**/*.map',
'packages/**/tests/**/*.d.ts',
'packages/**/tests/**/*.js',
'packages/**/tests/**/*.map',

'packages/**/*.md.backup',
'packages/**/*.tgz'
]);
});
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "0.9.0"
"version": "0.9.4"
}
32 changes: 32 additions & 0 deletions nx.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"targetDefaults": {
"compile": {
"clean": {
"dependsOn": [
"^clean"
]
},
"cache": true,
"dependsOn": [
"^compile"
],
"outputs": [
"{projectRoot}/packages/**/build/"
]
},
"test": {
"dependsOn": [
"^test"
]
},
"bumpversion": {
"dependsOn": []
},
"publish_library": {
"dependsOn": []
},
"test:github": {
"dependsOn": []
}
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"bugs": {
"url": "https://github.com/plblum/jivs/issues"
},
"private": true,
"private": "false",
"workspaces": [
"packages/*",
"starter_code/*"
Expand Down Expand Up @@ -44,7 +44,9 @@
"test": "jest",
"test:github": "jest --ci --reporters='default' --reporters='./.github/scripts/github-actions-reporter'",
"gulp": "node gulpfile.mjs",
"clean": "gulp clean"
"clean": "gulp clean",
"bumpversion": "lerna version --no-private",
"publish_library": "lerna publish --no-private"
},
"eslintConfig": {
"env": {
Expand Down
20 changes: 20 additions & 0 deletions packages/jivs-engine/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
tests/
/src/
coverage/
docs/
node_modules/
typedoc/
typedoc_output/
tsconfig*.json
typedoc.json
gulpfile.js
gulpfile.mjs
README.md.backup
jest.config.*
# .eslintignore
# .gitattributes
# .gitignore
# eslintrc.json
# packages-lock.json
# .github/
# .vscode/
21 changes: 21 additions & 0 deletions packages/jivs-engine/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Peter Blum

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
10 changes: 5 additions & 5 deletions packages/jivs-engine/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@
Jivs -- JavaScript Input Validation Service -- is a suite of libraries that help answer this question: how do I deal with data validation in the UI and/or on the Model?

Start here to better understand this library and determine if its right for you:
[http://jivs.peterblum.com/typedoc](Jivs Documentation)
[Jivs Documentation](http://jivs.peterblum.com/typedoc)

I don't want to repeat the same content in two places. So the document you are reading assumes you're familiar with it's core ideas.

*Jivs is a work-in-progress. This is a preview to get feedback from the community.
I'm looking for an assessment of the architecture. I've been tweaking and refactoring
it plenty in hopes its easy to use and really delivers. Getting the API right early on
it plenty in hopes it's easy to use and really delivers. Getting the API right early on
avoids the hassle of breaking changes later.*

*Please visit [https://github.com/plblum/jivs/discussions](Jivs Github Discussions board) to participate.*
*Please visit [Jivs Github Discussions board](https://github.com/plblum/jivs/discussions) to participate.*

Jivs includes multiple libraries. This one -- **jivs-engine** -- handles the actual work of validation. It provides no user interface and is unaware of the shape of any Model. Its written with a strong sense of modern OOP patterns, where you build something with a strong separation of concerns: the UI is a separate world from evaluating data and returning a result.

Expand All @@ -27,6 +27,6 @@ npm install --save @plblum/jivs-engine

## Usage
As this is a library that is behind other libraries, there are many ways to use Jivs.
So please use [http://jivs.peterblum.com/typedoc](Jivs Documentation) and the other Jivs libraries as a resource.
So please use [Jivs Documentation](http://jivs.peterblum.com/typedoc) and the other Jivs libraries as a resource.

In addition, the (https://github.com/plblum/jivs)[source code] includes a package called [https://github.com/plblum/jivs/tree/main/packages/jivs-examples](jivs-examples), dedicated to coding examples.
In addition, the [source code](https://github.com/plblum/jivs) includes a package called [jivs-examples](https://github.com/plblum/jivs/tree/main/packages/jivs-examples), dedicated to coding examples.
15 changes: 0 additions & 15 deletions packages/jivs-engine/gulpfile.js

This file was deleted.

51 changes: 51 additions & 0 deletions packages/jivs-engine/gulpfile.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Set NODE_PATH to the top-level node_modules directory
import { Module } from 'module';
process.env.NODE_PATH = '../../node_modules';

// Ensure that require() searches for modules in the specified directories
Module._initPaths();

import gulp from 'gulp';
import jestContainer from 'gulp-jest';
import { deleteAsync as del } from 'del';

let jest = jestContainer.default;

gulp.task('jest', function () {
process.env.NODE_ENV = 'test';
return gulp.default.src('tests').pipe(jest({
"config": "./jest.config.js"
}));
});


// Define the 'clean' task
gulp.task('clean', function () {
return del([
'coverage/**/*',
'build/**/*',
'src/**/*.d.ts',
// 'src/**/*.js',
'src/**/*.map',
'*.md.backup',
'*.tgz'
]);
});



// // Set NODE_PATH to the top-level node_modules directory
// process.env.NODE_PATH = '../../node_modules';

// // Ensure that require() searches for modules in the specified directories
// require('module').Module._initPaths();

// var gulp = require('gulp');
// var jest = require('gulp-jest').default;

// gulp.task('jest', function () {
// process.env.NODE_ENV = 'test';
// return gulp.src('tests').pipe(jest({
// "config": "./jest.config.js"
// }));
// });
Loading