adapt-project 1.0.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.
@@ -0,0 +1,191 @@
1
+ import _ from 'lodash'
2
+ import fs from 'fs-extra'
3
+
4
+ /**
5
+ * @typedef {import('../Framework')} Framework
6
+ * @typedef {import('../JSONFileItem')} JSONFileItem
7
+ * @typedef {import('../plugins/Plugin')} Plugin
8
+ */
9
+
10
+ class Schema {
11
+ /**
12
+ * @param {Object} options
13
+ * @param {Framework} options.framework
14
+ * @param {string} options.name
15
+ * @param {Plugin} options.plugin
16
+ * @param {Object} options.json
17
+ * @param {string} options.filePath
18
+ * @param {string} options.globalsType
19
+ */
20
+ constructor ({
21
+ framework = null,
22
+ name = '',
23
+ plugin = null,
24
+ json = null,
25
+ filePath = '',
26
+ globalsType = ''
27
+ } = {}) {
28
+ /** @type {Framework} */
29
+ this.framework = framework
30
+ /** @type {Plugin} */
31
+ this.plugin = plugin
32
+ /** @type {string} */
33
+ this.name = name
34
+ /** @type {Object} */
35
+ this.json = json
36
+ /** @type {string} */
37
+ this.filePath = filePath
38
+ /** @type {string} */
39
+ this.globalsType = globalsType
40
+ }
41
+
42
+ /** @returns {Schema} */
43
+ load () {
44
+ this.json = fs.readJSONSync(this.filePath)
45
+ return this
46
+ }
47
+
48
+ /**
49
+ * Walk through schema properties and an object's attributes calling an
50
+ * iterator function with the attributeName, attributeType and schema
51
+ * description along with the framework object, the current object attribute
52
+ * node and any other pass-through arguments.
53
+ * @param {string} schemaPath The attribute path from which to start in the schema
54
+ * @param {SchemaTraverseIterator} iterator
55
+ * @param {...any} args pass-through arguments
56
+ * @returns {Schema}
57
+ */
58
+ traverse (schemaPath, iterator, ...args) {
59
+ let shouldStop = false
60
+ const json = schemaPath ? _.get(this.json.properties, schemaPath) : this.json
61
+ const recursiveSchemaNodeProperties = (properties, ...args) => {
62
+ let rtnValue = false
63
+ // process properties
64
+ for (const attributeName in properties) {
65
+ let description = properties[attributeName]
66
+ if (Object.prototype.hasOwnProperty.call(description, 'editorOnly') || !Object.prototype.hasOwnProperty.call(description, 'type')) {
67
+ // go to next attribute
68
+ continue
69
+ }
70
+ description = { framework: this.framework, name: attributeName, ...description }
71
+ // process current properties attribute
72
+ const returned = iterator({
73
+ description,
74
+ next: (...args) => {
75
+ // continue with recursion if able
76
+ switch (description.type) {
77
+ case 'object':
78
+ return recursiveSchemaNodeProperties(description.properties, ...args)
79
+ case 'array': {
80
+ if (description.items.type === 'object') {
81
+ return recursiveSchemaNodeProperties(description.items.properties, ...args)
82
+ }
83
+ const next = {}
84
+ next[attributeName] = description.items
85
+ return recursiveSchemaNodeProperties(next, ...args)
86
+ }
87
+ }
88
+ },
89
+ stop: () => {
90
+ shouldStop = true
91
+ }
92
+ }, ...args)
93
+ rtnValue = rtnValue || returned
94
+ if (shouldStop) {
95
+ return
96
+ }
97
+ }
98
+ }
99
+ recursiveSchemaNodeProperties(json.properties, ...args)
100
+ return this
101
+ }
102
+
103
+ /**
104
+ * Applies schema defaults to the given object.
105
+ * @param {Object} output
106
+ * @param {string} schemaPath
107
+ * @param {Object} options
108
+ * @param {boolean} options.fillObjects Infer array or object default objects
109
+ * @returns {Schema}
110
+ */
111
+ applyDefaults (output = {}, schemaPath, options = { fillObjects: true }) {
112
+ function sortKeys (object) {
113
+ const keys = Object.keys(object).sort((a, b) => {
114
+ return a.localeCompare(b)
115
+ })
116
+ keys.forEach(name => {
117
+ const value = object[name]
118
+ delete object[name]
119
+ object[name] = value
120
+ })
121
+ return object
122
+ }
123
+
124
+ this.traverse(schemaPath, ({ description, next }, output) => {
125
+ let hasChanged = false
126
+ let haveChildenChanged = false
127
+ let defaultValue
128
+
129
+ if (description === null || output === null) return
130
+
131
+ switch (description.type) {
132
+ case 'object':
133
+ defaultValue = Object.prototype.hasOwnProperty.call(description, 'default') && options.fillObjects ? description.default : {}
134
+ if (!Object.prototype.hasOwnProperty.call(output, description.name)) {
135
+ output[description.name] = defaultValue
136
+ hasChanged = true
137
+ }
138
+ haveChildenChanged = next(output[description.name])
139
+ if (haveChildenChanged) {
140
+ sortKeys(output[description.name])
141
+ }
142
+ break
143
+ case 'array':
144
+ defaultValue = Object.prototype.hasOwnProperty.call(description, 'default') && options.fillObjects ? description.default : []
145
+ if (!Object.prototype.hasOwnProperty.call(output, description.name)) {
146
+ output[description.name] = defaultValue
147
+ hasChanged = true
148
+ }
149
+ haveChildenChanged = next(output[description.name])
150
+ if (haveChildenChanged) {
151
+ sortKeys(output[description.name])
152
+ }
153
+ break
154
+ default:
155
+ defaultValue = description.default
156
+ if (Object.prototype.hasOwnProperty.call(description, 'default') && !Object.prototype.hasOwnProperty.call(output, description.name)) {
157
+ output[description.name] = defaultValue
158
+ hasChanged = true
159
+ }
160
+ break
161
+ }
162
+ return hasChanged
163
+ }, output)
164
+
165
+ return output
166
+ }
167
+ }
168
+
169
+ /**
170
+ * @typedef SchemaNodeDescription
171
+ * @property {Framework} framework Schema properties node
172
+ * @property {string} name Attribute name
173
+ * @property {string} type Attribute type
174
+ * @property {boolean} editorOnly
175
+ */
176
+
177
+ /**
178
+ * @typedef SchemaTraverseIteratorParam0
179
+ * @property {SchemaNodeDescription} description
180
+ * @property {function} next
181
+ * @property {function} stop
182
+ */
183
+
184
+ /**
185
+ * Iterator function for schema.traverse.
186
+ * @callback SchemaTraverseIterator
187
+ * @param {SchemaTraverseIteratorParam0} config
188
+ * @param {...any} args pass-through arguments
189
+ */
190
+
191
+ export default Schema
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "adapt-project",
3
+ "version": "1.0.0",
4
+ "description": "Adapt Framework project helpers - plugins, schemas, data and translations",
5
+ "main": "index.js",
6
+ "type": "module",
7
+ "license": "GPL-3.0",
8
+ "scripts": {
9
+ "lint": "eslint .",
10
+ "lint:fix": "eslint . --fix"
11
+ },
12
+ "dependencies": {
13
+ "async": "^3.2.2",
14
+ "chalk": "^2.4.1",
15
+ "csv": "^5.5.3",
16
+ "fast-xml-parser": "^4.5.0",
17
+ "fs-extra": "^8.1.0",
18
+ "globs": "^0.1.4",
19
+ "iconv-lite": "^0.6.3",
20
+ "jschardet": "^1.6.0",
21
+ "lodash": "^4.17.23",
22
+ "semver": "^7.6.0"
23
+ },
24
+ "devDependencies": {
25
+ "@semantic-release/git": "^10.0.1",
26
+ "conventional-changelog-eslint": "^6.0.0",
27
+ "semantic-release": "^25.0.3",
28
+ "@eslint/eslintrc": "^3.1.0",
29
+ "eslint": "^8.57.0",
30
+ "eslint-config-standard": "^17.1.0",
31
+ "eslint-plugin-import": "^2.29.0",
32
+ "eslint-plugin-n": "^16.6.0",
33
+ "eslint-plugin-promise": "^6.6.0"
34
+ },
35
+ "release": {
36
+ "plugins": [
37
+ [
38
+ "@semantic-release/commit-analyzer",
39
+ {
40
+ "preset": "eslint"
41
+ }
42
+ ],
43
+ [
44
+ "@semantic-release/release-notes-generator",
45
+ {
46
+ "preset": "eslint"
47
+ }
48
+ ],
49
+ "@semantic-release/npm",
50
+ "@semantic-release/github",
51
+ "@semantic-release/git"
52
+ ]
53
+ }
54
+ }