@iqb/validate-md-profile 0.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 +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/md-profile.schema.json +204 -0
- package/dist/validate-md-profile.d.ts +1 -0
- package/dist/validate-md-profile.js +82 -0
- package/dist/validate-md-profile.js.map +1 -0
- package/package.json +36 -0
- package/src/index.ts +1 -0
- package/src/validate-md-profile.ts +74 -0
- package/tsconfig.json +18 -0
package/README.md
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./validate-md-profile";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./validate-md-profile"), exports);
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$id": "https://w3id.org/iqb/vocabs/md-profile.json",
|
|
3
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
4
|
+
"title": "Metadata Profile",
|
|
5
|
+
"description": "Data structure to manage UI components for metadata of objects",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"properties": {
|
|
8
|
+
"id": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Identifier for the metadata profile"
|
|
11
|
+
},
|
|
12
|
+
"label": {
|
|
13
|
+
"$ref": "#/definitions/multi_language_text",
|
|
14
|
+
"description": "Name of the profile"
|
|
15
|
+
},
|
|
16
|
+
"groups": {
|
|
17
|
+
"type": "array",
|
|
18
|
+
"items": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"properties": {
|
|
21
|
+
"label": {
|
|
22
|
+
"$ref": "#/definitions/multi_language_text"
|
|
23
|
+
},
|
|
24
|
+
"entries": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": {
|
|
27
|
+
"$ref": "#/definitions/entry"
|
|
28
|
+
},
|
|
29
|
+
"minItems": 1
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"required": ["label", "entries"]
|
|
33
|
+
},
|
|
34
|
+
"minItems": 1
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"required": ["id", "label", "groups"],
|
|
38
|
+
"definitions": {
|
|
39
|
+
"multi_language_text": {
|
|
40
|
+
"type": "array",
|
|
41
|
+
"items": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"lang": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"description": "ISO-language code",
|
|
47
|
+
"pattern": "^[a-z]{2}$"
|
|
48
|
+
},
|
|
49
|
+
"value": {
|
|
50
|
+
"type": "string"
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
"required": ["lang", "value"]
|
|
54
|
+
},
|
|
55
|
+
"minItems": 1
|
|
56
|
+
},
|
|
57
|
+
"vocabulary": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"description": "Creates values of type string (one possible id), string[] (multiple ids) or id+text tuples, if text input is allowed (see md-values).",
|
|
60
|
+
"properties": {
|
|
61
|
+
"url": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"description": "URI to the JSON representation (SkoHub) of the vocabulary definition"
|
|
64
|
+
},
|
|
65
|
+
"allowMultipleValues": {
|
|
66
|
+
"type": "boolean",
|
|
67
|
+
"description": "If true, multiple values are allowed taken from the vocabulary",
|
|
68
|
+
"default": false
|
|
69
|
+
},
|
|
70
|
+
"maxLevel": {
|
|
71
|
+
"type": "integer",
|
|
72
|
+
"description": "Maximum level taken from the hierarchical vocabulary. This is to hide lower levels. Use '0' for all levels (default).",
|
|
73
|
+
"default": 0
|
|
74
|
+
},
|
|
75
|
+
"hideNumbering": {
|
|
76
|
+
"type": "boolean",
|
|
77
|
+
"description": "If true, the numbering of vocabulary entries is not used/showed in components.",
|
|
78
|
+
"default": false
|
|
79
|
+
},
|
|
80
|
+
"hideDescription": {
|
|
81
|
+
"type": "boolean",
|
|
82
|
+
"description": "If true, the description of vocabulary entries is not used/showed in components.",
|
|
83
|
+
"default": false
|
|
84
|
+
},
|
|
85
|
+
"hideTitle": {
|
|
86
|
+
"type": "boolean",
|
|
87
|
+
"description": "If true, the title of vocabulary entries is not used/showed in components.",
|
|
88
|
+
"default": false
|
|
89
|
+
},
|
|
90
|
+
"addTextLanguages": {
|
|
91
|
+
"type": "array",
|
|
92
|
+
"items": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"description": "ISO-language code",
|
|
95
|
+
"pattern": "^[a-z]{2}$"
|
|
96
|
+
},
|
|
97
|
+
"description": "If not empty, text can be added to the selected vocabulary entry. The given entries specify the expected language(s).",
|
|
98
|
+
"default": []
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"required": ["url"]
|
|
102
|
+
},
|
|
103
|
+
"text": {
|
|
104
|
+
"type": "object",
|
|
105
|
+
"description": "Creates values of type string (one possible language) or multi-language texts (see md-values).",
|
|
106
|
+
"properties": {
|
|
107
|
+
"format": {
|
|
108
|
+
"type": "string",
|
|
109
|
+
"enum": ["single", "multiline", "html"],
|
|
110
|
+
"description": "If true, more then one line of text is prepared for input. Text is wrapped and vertical scrolling is possible.",
|
|
111
|
+
"default": "single"
|
|
112
|
+
},
|
|
113
|
+
"textLanguages": {
|
|
114
|
+
"type": "array",
|
|
115
|
+
"items": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"description": "ISO-language code",
|
|
118
|
+
"pattern": "^[a-z]{2}$"
|
|
119
|
+
},
|
|
120
|
+
"description": "Use this property to add languages, so you provide more then one text input form field.",
|
|
121
|
+
"default": [
|
|
122
|
+
"de"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
"pattern": {
|
|
126
|
+
"type": "string",
|
|
127
|
+
"description": "Use this regular expression to validate the input value."
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"number": {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"description": "Creates values of type string with number content. The decimal separator is always dot '.'.",
|
|
134
|
+
"properties": {
|
|
135
|
+
"digits": {
|
|
136
|
+
"type": "integer",
|
|
137
|
+
"description": "Number of digits. Negative values are not valid.",
|
|
138
|
+
"minimum": 0,
|
|
139
|
+
"default": 0
|
|
140
|
+
},
|
|
141
|
+
"minValue": {
|
|
142
|
+
"type": "number",
|
|
143
|
+
"description": "Minimal value valid for this entry."
|
|
144
|
+
},
|
|
145
|
+
"maxValue": {
|
|
146
|
+
"type": "number",
|
|
147
|
+
"description": "Maximal value valid for this entry."
|
|
148
|
+
},
|
|
149
|
+
"isPeriodSeconds": {
|
|
150
|
+
"type": "boolean",
|
|
151
|
+
"description": "If true, the (integer) value is interpreted as a number of seconds (duration, time period). This might adapt the form controls.",
|
|
152
|
+
"default": false
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"boolean": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"description": "Creates values of type string 'true' or 'false'.",
|
|
159
|
+
"properties": {
|
|
160
|
+
"trueLabel": {
|
|
161
|
+
"$ref": "#/definitions/multi_language_text"
|
|
162
|
+
},
|
|
163
|
+
"falseLabel": {
|
|
164
|
+
"$ref": "#/definitions/multi_language_text"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
"entry": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"properties": {
|
|
171
|
+
"id": {
|
|
172
|
+
"type": "string",
|
|
173
|
+
"pattern": "^[a-zA-Z][0-9a-zA-Z_]*$",
|
|
174
|
+
"description": "Identifier for the property as part of the metadata profile"
|
|
175
|
+
},
|
|
176
|
+
"label": {
|
|
177
|
+
"$ref": "#/definitions/multi_language_text",
|
|
178
|
+
"description": "Text presented in UI components as prompt"
|
|
179
|
+
},
|
|
180
|
+
"type": {
|
|
181
|
+
"type": "string",
|
|
182
|
+
"enum": ["text", "vocabulary", "boolean", "number"]
|
|
183
|
+
},
|
|
184
|
+
"parameters": {
|
|
185
|
+
"anyOf": [
|
|
186
|
+
{
|
|
187
|
+
"$ref": "#/definitions/vocabulary"
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
"$ref": "#/definitions/text"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"$ref": "#/definitions/number"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"$ref": "#/definitions/boolean"
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
"required": ["id", "type"]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var ajv_1 = require("ajv");
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var schemaFilename = 'md-profile.schema.json';
|
|
6
|
+
var fileToCheckName = './profile.json';
|
|
7
|
+
var schema = null;
|
|
8
|
+
if (process.argv[2]) {
|
|
9
|
+
fileToCheckName = "./".concat(process.argv[2]);
|
|
10
|
+
}
|
|
11
|
+
if (!fs.existsSync(fileToCheckName)) {
|
|
12
|
+
console.log("\u001B[0;31mERROR\u001B[0m profile file '".concat(fileToCheckName, "' not found"));
|
|
13
|
+
process.exitCode = 1;
|
|
14
|
+
}
|
|
15
|
+
else {
|
|
16
|
+
var schemaFullFilename = "".concat(__dirname, "/").concat(schemaFilename);
|
|
17
|
+
if (!fs.existsSync(schemaFullFilename)) {
|
|
18
|
+
schemaFullFilename = "./json_schema/md-profile/".concat(schemaFilename);
|
|
19
|
+
}
|
|
20
|
+
if (!fs.existsSync(schemaFullFilename)) {
|
|
21
|
+
console.log("\u001B[0;31mERROR\u001B[0m profile file '".concat(schemaFilename, "' not found"));
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
try {
|
|
26
|
+
schema = fs.readFileSync(schemaFullFilename, 'utf8');
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.log("\u001B[0;31mERROR\u001B[0m reading schema '".concat(schemaFilename, "':"));
|
|
30
|
+
console.error(err);
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
schema = null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (schema) {
|
|
37
|
+
var compiledSchema = void 0;
|
|
38
|
+
var ajv = new ajv_1.default(); // options can be passed, e.g. {allErrors: true}
|
|
39
|
+
try {
|
|
40
|
+
compiledSchema = ajv.compile(JSON.parse(schema));
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
console.log("\u001B[0;31mERROR\u001B[0m parsing schema '".concat(schemaFilename, "':"));
|
|
44
|
+
console.error(err);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
compiledSchema = null;
|
|
47
|
+
}
|
|
48
|
+
if (compiledSchema) {
|
|
49
|
+
var profileData = void 0;
|
|
50
|
+
try {
|
|
51
|
+
var profile_data_raw = fs.readFileSync(fileToCheckName, 'utf8');
|
|
52
|
+
profileData = JSON.parse(profile_data_raw);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.log("\u001B[0;31mERROR\u001B[0m reading and parsing config file '".concat(fileToCheckName, "':"));
|
|
56
|
+
console.error(err);
|
|
57
|
+
profileData = null;
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
}
|
|
60
|
+
if (profileData) {
|
|
61
|
+
try {
|
|
62
|
+
var valid = compiledSchema ? compiledSchema(profileData) : null;
|
|
63
|
+
if (valid) {
|
|
64
|
+
console.log("'".concat(fileToCheckName, "' is valid"));
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.log("\u001B[0;31mERROR\u001B[0m invalid profile file '".concat(fileToCheckName, "':"));
|
|
68
|
+
console.error(compiledSchema ? compiledSchema.errors : 'error unknown');
|
|
69
|
+
profileData = null;
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.log("\u001B[0;31mERROR\u001B[0m invalid profile file '".concat(fileToCheckName, "':"));
|
|
75
|
+
console.error(err);
|
|
76
|
+
profileData = null;
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=validate-md-profile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-md-profile.js","sourceRoot":"","sources":["../src/validate-md-profile.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iqb/validate-md-profile",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"author": "IQB - Institut zur Qualitätsentwicklung im Bildungswesen",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"description": "Data interfaces for metadata profiling and values",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test_profile": "ts-node ./test.ts md-profile",
|
|
9
|
+
"test_value": "ts-node ./test.ts md-values",
|
|
10
|
+
"validate_profile": "ts-node src/validate-md-profile.ts json_schema/md-profile/test_valid/sample_1.json",
|
|
11
|
+
"generate_docs": "asyncapi generate fromTemplate json_schema/asyncapi.yaml @asyncapi/html-template -o ./public --force-write && cat json_schema/add.css >> ./public/css/global.min.css",
|
|
12
|
+
"prepare_publish": "rm -rf dist/* && tsc && cp ./json_schema/md-profile/md-profile.schema.json ./dist",
|
|
13
|
+
"npm_publish": "npm publish --access public"
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/iqb-vocabs/profiles.git"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/iqb-vocabs/profiles/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/iqb-vocabs/profiles#readme",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"ajv": "^8.12.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@asyncapi/cli": "^0.58.10",
|
|
28
|
+
"@asyncapi/html-template": "^1.0.0",
|
|
29
|
+
"@types/node": "^20.4.4",
|
|
30
|
+
"ts-node": "^10.9.1",
|
|
31
|
+
"typescript": "^5.2.2"
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"validate-md-profile": "./dist/validate-md-profile.js"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./validate-md-profile";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import Ajv from "ajv";
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const schemaFilename = 'md-profile.schema.json';
|
|
5
|
+
let fileToCheckName = './profile.json';
|
|
6
|
+
let schema = null;
|
|
7
|
+
if (process.argv[2]) {
|
|
8
|
+
fileToCheckName = `./${process.argv[2]}`;
|
|
9
|
+
}
|
|
10
|
+
if (!fs.existsSync(fileToCheckName)) {
|
|
11
|
+
console.log(`\x1b[0;31mERROR\x1b[0m profile file '${fileToCheckName}' not found`);
|
|
12
|
+
process.exitCode = 1;
|
|
13
|
+
} else {
|
|
14
|
+
let schemaFullFilename = `${__dirname}/${schemaFilename}`;
|
|
15
|
+
if (!fs.existsSync(schemaFullFilename)) {
|
|
16
|
+
schemaFullFilename = `./json_schema/md-profile/${schemaFilename}`;
|
|
17
|
+
}
|
|
18
|
+
if (!fs.existsSync(schemaFullFilename)) {
|
|
19
|
+
console.log(`\x1b[0;31mERROR\x1b[0m profile file '${schemaFilename}' not found`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
} else {
|
|
22
|
+
try {
|
|
23
|
+
schema = fs.readFileSync(schemaFullFilename, 'utf8');
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.log(`\x1b[0;31mERROR\x1b[0m reading schema '${schemaFilename}':`);
|
|
26
|
+
console.error(err);
|
|
27
|
+
process.exitCode = 1;
|
|
28
|
+
schema = null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (schema) {
|
|
34
|
+
let compiledSchema;
|
|
35
|
+
const ajv = new Ajv() // options can be passed, e.g. {allErrors: true}
|
|
36
|
+
try {
|
|
37
|
+
compiledSchema = ajv.compile(JSON.parse(schema))
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.log(`\x1b[0;31mERROR\x1b[0m parsing schema '${schemaFilename}':`);
|
|
40
|
+
console.error(err);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
compiledSchema = null;
|
|
43
|
+
}
|
|
44
|
+
if (compiledSchema) {
|
|
45
|
+
let profileData;
|
|
46
|
+
try {
|
|
47
|
+
const profile_data_raw = fs.readFileSync(fileToCheckName, 'utf8');
|
|
48
|
+
profileData = JSON.parse(profile_data_raw);
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.log(`\x1b[0;31mERROR\x1b[0m reading and parsing config file '${fileToCheckName}':`);
|
|
51
|
+
console.error(err);
|
|
52
|
+
profileData = null;
|
|
53
|
+
process.exitCode = 1;
|
|
54
|
+
}
|
|
55
|
+
if (profileData) {
|
|
56
|
+
try {
|
|
57
|
+
const valid = compiledSchema ? compiledSchema(profileData) : null;
|
|
58
|
+
if (valid) {
|
|
59
|
+
console.log(`'${fileToCheckName}' is valid`);
|
|
60
|
+
} else {
|
|
61
|
+
console.log(`\x1b[0;31mERROR\x1b[0m invalid profile file '${fileToCheckName}':`);
|
|
62
|
+
console.error(compiledSchema ? compiledSchema.errors : 'error unknown')
|
|
63
|
+
profileData = null;
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
}
|
|
66
|
+
} catch (err) {
|
|
67
|
+
console.log(`\x1b[0;31mERROR\x1b[0m invalid profile file '${fileToCheckName}':`);
|
|
68
|
+
console.error(err);
|
|
69
|
+
profileData = null;
|
|
70
|
+
process.exitCode = 1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"declaration": true,
|
|
4
|
+
"strictNullChecks": true,
|
|
5
|
+
"strict": true,
|
|
6
|
+
"target": "es5",
|
|
7
|
+
"module": "commonjs",
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"outDir": "dist",
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"lib": ["es2015", "dom", "es2021"],
|
|
13
|
+
"rootDir": "src",
|
|
14
|
+
"allowSyntheticDefaultImports": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src"],
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|