schema-markdown 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -85,8 +85,8 @@ try {
85
85
 
86
86
  ## Development
87
87
 
88
- This project is developed using [javascript-build](https://github.com/craigahobbs/javascript-build#readme). It was started
89
- using [javascript-template](https://github.com/craigahobbs/javascript-template#readme) as follows:
88
+ schema-markdown is developed using [javascript-build](https://github.com/craigahobbs/javascript-build#readme)
89
+ and it was started using [javascript-template](https://github.com/craigahobbs/javascript-template#readme):
90
90
 
91
91
  ```
92
92
  template-specialize javascript-template/template/ schema-markdown-js/ -k package schema-markdown -k name 'Craig A. Hobbs' -k email 'craigahobbs@gmail.com' -k github 'craigahobbs' -k noapp 1
package/lib/encode.js ADDED
@@ -0,0 +1,130 @@
1
+ // Licensed under the MIT License
2
+ // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
+
4
+ /** @module lib/encode */
5
+
6
+
7
+ /**
8
+ * Encode an object as a query/hash string. Dictionaries, lists, and tuples are recursed. Each member key is expressed
9
+ * in fully-qualified form. List keys are the index into the list, and are in order.
10
+ *
11
+ * @param {Object} obj - The parameters object
12
+ * @returns {string}
13
+ */
14
+ export function encodeQueryString(obj) {
15
+ return encodeQueryStringHelper(obj).join('&');
16
+ }
17
+
18
+
19
+ // Helper function for encodeQueryString
20
+ function encodeQueryStringHelper(obj, memberFqn = null, keyValues = []) {
21
+ const objType = typeof obj;
22
+ if (Array.isArray(obj)) {
23
+ if (obj.length === 0) {
24
+ keyValues.push(memberFqn !== null ? `${memberFqn}=` : '');
25
+ } else {
26
+ for (let ix = 0; ix < obj.length; ix++) {
27
+ encodeQueryStringHelper(obj[ix], memberFqn !== null ? `${memberFqn}.${ix}` : `${ix}`, keyValues);
28
+ }
29
+ }
30
+ } else if (obj instanceof Date) {
31
+ const objEncoded = encodeURIComponent(obj.toISOString());
32
+ keyValues.push(memberFqn !== null ? `${memberFqn}=${objEncoded}` : `${objEncoded}`);
33
+ } else if (obj !== null && typeof obj === 'object') {
34
+ const keys = Object.keys(obj).sort();
35
+ if (keys.length === 0) {
36
+ keyValues.push(memberFqn !== null ? `${memberFqn}=` : '');
37
+ } else {
38
+ for (const key of keys) {
39
+ const keyEncoded = encodeQueryStringHelper(key);
40
+ encodeQueryStringHelper(obj[key], memberFqn !== null ? `${memberFqn}.${keyEncoded}` : `${keyEncoded}`, keyValues);
41
+ }
42
+ }
43
+ } else if (obj === null || objType === 'boolean' || objType === 'number') {
44
+ keyValues.push(memberFqn !== null ? `${memberFqn}=${obj}` : `${obj}`);
45
+ } else {
46
+ const objEncoded = encodeURIComponent(obj);
47
+ keyValues.push(memberFqn !== null ? `${memberFqn}=${objEncoded}` : `${objEncoded}`);
48
+ }
49
+ return keyValues;
50
+ }
51
+
52
+
53
+ /**
54
+ * Decode an object from a query/hash string. Each member key of the query string is expressed in fully-qualified
55
+ * form. List keys are the index into the list, must be in order.
56
+ *
57
+ * @param {string} paramStr - The parameters string
58
+ * @returns {Object}
59
+ */
60
+ export function decodeQueryString(paramStr) {
61
+ // Decode the parameter string key/values
62
+ const result = [null];
63
+ const keyValues = paramStr.split('&');
64
+ keyValues.forEach((keyValue, ixKeyValue) => {
65
+ const [keyFqn, valueEncoded = null] = keyValue.split('=', 2);
66
+ if (valueEncoded === null) {
67
+ // Ignore hash IDs
68
+ if (ixKeyValue === keyValues.length - 1) {
69
+ return;
70
+ }
71
+ throw new Error(`Invalid key/value pair '${keyValue.slice(0, 100)}'`);
72
+ }
73
+ const value = decodeURIComponent(valueEncoded);
74
+
75
+ // Find/create the object on which to set the value
76
+ let parent = result;
77
+ let keyParent = 0;
78
+ const keys = keyFqn.split('.');
79
+ for (const keyEncoded of keys) {
80
+ let key = decodeURIComponent(keyEncoded);
81
+ let obj = parent[keyParent];
82
+
83
+ // Array key? First "key" of an array must start with "0".
84
+ if (Array.isArray(obj) || (obj === null && key === '0')) {
85
+ // Create this key's container, if necessary
86
+ if (obj === null) {
87
+ obj = [];
88
+ parent[keyParent] = obj;
89
+ }
90
+
91
+ // Parse the key as an integer
92
+ if (isNaN(key)) {
93
+ throw new Error(`Invalid array index '${key.slice(0, 100)}' in key '${keyFqn.slice(0, 100)}'`);
94
+ }
95
+ const keyOrig = key;
96
+ key = parseInt(key, 10);
97
+
98
+ // Append the value placeholder null
99
+ if (key === obj.length) {
100
+ obj.push(null);
101
+ } else if (key < 0 || key > obj.length) {
102
+ throw new Error(`Invalid array index '${keyOrig.slice(0, 100)}' in key '${keyFqn.slice(0, 100)}'`);
103
+ }
104
+ } else {
105
+ // Create this key's container, if necessary
106
+ if (obj === null) {
107
+ obj = {};
108
+ parent[keyParent] = obj;
109
+ }
110
+
111
+ // Create the index for this key
112
+ if (!(key in obj)) {
113
+ obj[key] = null;
114
+ }
115
+ }
116
+
117
+ // Update the parent object and key
118
+ parent = obj;
119
+ keyParent = key;
120
+ }
121
+
122
+ // Set the value
123
+ if (parent[keyParent] !== null) {
124
+ throw new Error(`Duplicate key '${keyFqn.slice(0, 100)}'`);
125
+ }
126
+ parent[keyParent] = value;
127
+ });
128
+
129
+ return result[0] !== null ? result[0] : {};
130
+ }
@@ -1,6 +1,8 @@
1
1
  // Licensed under the MIT License
2
2
  // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
3
 
4
+ /** @module lib/parser */
5
+
4
6
  import {validateTypeModelTypesErrors} from './schemaUtil.js';
5
7
 
6
8
  /* eslint-disable prefer-template */
@@ -1,6 +1,8 @@
1
1
  // Licensed under the MIT License
2
2
  // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
3
 
4
+ /** @module lib/schema */
5
+
4
6
  import {typeModel} from './typeModel.js';
5
7
  import {validateTypeModelTypesErrors} from './schemaUtil.js';
6
8
 
@@ -97,7 +99,7 @@ function getReferencedTypesHelper(types, type, referencedTypes) {
97
99
  /**
98
100
  * Schema Markdown type model validation error
99
101
  *
100
- * @property {?string} memberFqn - The list of error strings
102
+ * @property {?string} memberFqn - The fully qualified member name
101
103
  */
102
104
  export class ValidationError extends Error {
103
105
  /**
@@ -194,13 +196,13 @@ function validateTypeHelper(types, type, value, memberFqn) {
194
196
  } else if (builtin === 'date' || builtin === 'datetime') {
195
197
  // Convert string?
196
198
  if (typeof value === 'string') {
197
- valueNew = new Date(value);
198
- if (isNaN(valueNew)) {
199
- throwMemberError(type, value, memberFqn);
200
- }
201
-
202
- // Invalid date format?
203
- if (!(rDate.test(value) || rDatetime.test(value))) {
199
+ // Valid date format?
200
+ if (rDate.test(value)) {
201
+ const localDate = new Date(value);
202
+ valueNew = new Date(localDate.getUTCFullYear(), localDate.getUTCMonth(), localDate.getUTCDate());
203
+ } else if (rDatetime.test(value)) {
204
+ valueNew = new Date(value);
205
+ } else {
204
206
  throwMemberError(type, value, memberFqn);
205
207
  }
206
208
 
File without changes
@@ -1,6 +1,8 @@
1
1
  // Licensed under the MIT License
2
2
  // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
3
 
4
+ /** @module lib/typeModel */
5
+
4
6
  import {SchemaMarkdownParser} from './parser.js';
5
7
 
6
8
 
@@ -251,7 +253,9 @@ struct ActionURL
251
253
  `;
252
254
 
253
255
 
254
- // The Schema Markdown type model
256
+ /**
257
+ * The Schema Markdown type model
258
+ */
255
259
  export const typeModel = {
256
260
  'title': 'The Schema Markdown Type Model',
257
261
  'types': (new SchemaMarkdownParser(typeModelSmd)).types
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "schema-markdown",
4
- "version": "1.0.3",
4
+ "version": "1.1.0",
5
5
  "description": "Human-friendly schema definition language and schema validator",
6
6
  "keywords": [
7
7
  "schema",
@@ -18,17 +18,16 @@
18
18
  "url": "https://github.com/craigahobbs"
19
19
  },
20
20
  "files": [
21
- "index.js",
22
- "src/schema-markdown/**/*"
21
+ "lib/**/*"
23
22
  ],
24
23
  "scripts": {
25
- "test": "ava -v 'src/tests/**/*.js'"
24
+ "test": "ava -v test/"
26
25
  },
27
26
  "devDependencies": {
28
- "ava": "4.0.0-alpha.2",
29
- "c8": "7.8.0",
30
- "eslint": "7.32.0",
31
- "jsdoc": "3.6.7",
32
- "window": "4.2.7"
27
+ "ava": "^4.0.0-rc.1",
28
+ "c8": "~7.10",
29
+ "eslint": "~8.3",
30
+ "jsdoc": "~3.6",
31
+ "jsdom": "~18.1"
33
32
  }
34
33
  }
package/index.js DELETED
@@ -1,4 +0,0 @@
1
- // Licensed under the MIT License
2
- // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
-
4
- export * from './src/schema-markdown/index.js';
@@ -1,129 +0,0 @@
1
- // Licensed under the MIT License
2
- // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
-
4
-
5
- /**
6
- * Encode an object as a query/hash string. Dictionaries, lists, and tuples are recursed. Each member key is expressed
7
- * in fully-qualified form. List keys are the index into the list, and are in order.
8
- *
9
- * @param {Object} obj - The parameters object
10
- * @returns {string}
11
- */
12
- export function encodeQueryString(obj) {
13
- return encodeQueryStringHelper(obj).join('&');
14
- }
15
-
16
-
17
- // Helper function for encodeQueryString
18
- function encodeQueryStringHelper(obj, memberFqn = null, keyValues = []) {
19
- const objType = typeof obj;
20
- if (Array.isArray(obj)) {
21
- if (obj.length === 0) {
22
- keyValues.push(memberFqn !== null ? `${memberFqn}=` : '');
23
- } else {
24
- for (let ix = 0; ix < obj.length; ix++) {
25
- encodeQueryStringHelper(obj[ix], memberFqn !== null ? `${memberFqn}.${ix}` : `${ix}`, keyValues);
26
- }
27
- }
28
- } else if (obj instanceof Date) {
29
- const objEncoded = encodeURIComponent(obj.toISOString());
30
- keyValues.push(memberFqn !== null ? `${memberFqn}=${objEncoded}` : `${objEncoded}`);
31
- } else if (obj !== null && typeof obj === 'object') {
32
- const keys = Object.keys(obj).sort();
33
- if (keys.length === 0) {
34
- keyValues.push(memberFqn !== null ? `${memberFqn}=` : '');
35
- } else {
36
- for (const key of keys) {
37
- const keyEncoded = encodeQueryStringHelper(key);
38
- encodeQueryStringHelper(obj[key], memberFqn !== null ? `${memberFqn}.${keyEncoded}` : `${keyEncoded}`, keyValues);
39
- }
40
- }
41
- } else if (obj === null || objType === 'boolean' || objType === 'number') {
42
- keyValues.push(memberFqn !== null ? `${memberFqn}=${obj}` : `${obj}`);
43
- } else {
44
- const objEncoded = encodeURIComponent(obj);
45
- keyValues.push(memberFqn !== null ? `${memberFqn}=${objEncoded}` : `${objEncoded}`);
46
- }
47
- return keyValues;
48
- }
49
-
50
-
51
- /**
52
- * Decode an object from a query/hash string. Each member key of the query string is expressed in fully-qualified
53
- * form. List keys are the index into the list, must be in order.
54
- *
55
- * @param {string} paramStr - The parameters string
56
- * @returns {Object}
57
- */
58
- export function decodeQueryString(paramStr) {
59
- // Decode the parameter string key/values
60
- const result = [null];
61
- paramStr.split('&').filter((keyValue) => keyValue.length).forEach(
62
- (keyValue, ixKeyValue, keyValuesFiltered) => {
63
- const [keyFqn, valueEncoded = null] = keyValue.split('=');
64
- if (valueEncoded === null) {
65
- // Ignore anchor tags
66
- if (ixKeyValue === keyValuesFiltered.length - 1) {
67
- return;
68
- }
69
- throw new Error(`Invalid key/value pair '${keyValue.slice(0, 100)}'`);
70
- }
71
- const value = decodeURIComponent(valueEncoded);
72
-
73
- // Find/create the object on which to set the value
74
- let parent = result;
75
- let keyParent = 0;
76
- const keys = keyFqn.split('.');
77
- for (const keyEncoded of keys) {
78
- let key = decodeURIComponent(keyEncoded);
79
- let obj = parent[keyParent];
80
-
81
- // Array key? First "key" of an array must start with "0".
82
- if (Array.isArray(obj) || (obj === null && key === '0')) {
83
- // Create this key's container, if necessary
84
- if (obj === null) {
85
- obj = [];
86
- parent[keyParent] = obj;
87
- }
88
-
89
- // Parse the key as an integer
90
- if (isNaN(key)) {
91
- throw new Error(`Invalid array index '${key.slice(0, 100)}' in key '${keyFqn.slice(0, 100)}'`);
92
- }
93
- const keyOrig = key;
94
- key = parseInt(key, 10);
95
-
96
- // Append the value placeholder null
97
- if (key === obj.length) {
98
- obj.push(null);
99
- } else if (key < 0 || key > obj.length) {
100
- throw new Error(`Invalid array index '${keyOrig.slice(0, 100)}' in key '${keyFqn.slice(0, 100)}'`);
101
- }
102
- } else {
103
- // Create this key's container, if necessary
104
- if (obj === null) {
105
- obj = {};
106
- parent[keyParent] = obj;
107
- }
108
-
109
- // Create the index for this key
110
- if (!(key in obj)) {
111
- obj[key] = null;
112
- }
113
- }
114
-
115
- // Update the parent object and key
116
- parent = obj;
117
- keyParent = key;
118
- }
119
-
120
- // Set the value
121
- if (parent[keyParent] !== null) {
122
- throw new Error(`Duplicate key '${keyFqn.slice(0, 100)}'`);
123
- }
124
- parent[keyParent] = value;
125
- }
126
- );
127
-
128
- return result[0] !== null ? result[0] : {};
129
- }
@@ -1,26 +0,0 @@
1
- // Licensed under the MIT License
2
- // https://github.com/craigahobbs/schema-markdown-js/blob/main/LICENSE
3
-
4
- export {
5
- decodeQueryString,
6
- encodeQueryString
7
- } from './encode.js';
8
-
9
- export {
10
- SchemaMarkdownParser,
11
- SchemaMarkdownParserError
12
- } from './parser.js';
13
-
14
- export {
15
- ValidationError,
16
- getEnumValues,
17
- getReferencedTypes,
18
- getStructMembers,
19
- validateType,
20
- validateTypeModel,
21
- validateTypeModelTypes
22
- } from './schema.js';
23
-
24
- export {
25
- typeModel
26
- } from './typeModel.js';