Project

General

Profile

Download (6.36 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / common / entities.js @ 1f9ccef9

1
/**
2
 * This file is part of Haketilo.
3
 *
4
 * Function: Operations on resources and mappings.
5
 *
6
 * Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * As additional permission under GNU GPL version 3 section 7, you
19
 * may distribute forms of that code without the copy of the GNU
20
 * GPL normally required by section 4, provided you include this
21
 * license notice and, in case of non-source distribution, a URL
22
 * through which recipients can access the Corresponding Source.
23
 * If you modify file(s) with this exception, you may extend this
24
 * exception to your version of the file(s), but you are not
25
 * obligated to do so. If you do not wish to do so, delete this
26
 * exception statement from your version.
27
 *
28
 * As a special exception to the GPL, any HTML file which merely
29
 * makes function calls to this code, and for that purpose
30
 * includes it by reference shall be deemed a separate work for
31
 * copyright law purposes. If you modify this code, you may extend
32
 * this exception to your version of the code, but you are not
33
 * obligated to do so. If you do not wish to do so, delete this
34
 * exception statement from your version.
35
 *
36
 * You should have received a copy of the GNU General Public License
37
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
38
 *
39
 * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
40
 * license. Although I request that you do not make use of this code in a
41
 * proprietary program, I am not going to enforce this in court.
42
 */
43

    
44
/*
45
 * Convert ver_str into an array representation, e.g. for ver_str="4.6.13.0"
46
 * return [4, 6, 13, 0].
47
 */
48
const parse_version = ver_str => ver_str.split(".").map(n => parseInt(n));
49

    
50
/*
51
 * ver is an array of integers. rev is an optional integer. Produce string
52
 * representation of version (optionally with revision number), like:
53
 *     1.2.3-5
54
 * No version normalization is performed.
55
 */
56
const version_string = (ver, rev=0) => ver.join(".") + (rev ? `-${rev}` : "");
57
#EXPORT version_string
58

    
59
/*
60
 * This function overloads on the number of arguments. If one argument is
61
 * passed, it is an item definition (it need not be complete, only identifier,
62
 * version and, if applicable, revision properties are relevant). If two or
63
 * three arguments are given, they are in order: item identifier, item version
64
 * and item revision.
65
 * Returned is a string identifying this version of item.
66
 */
67
function item_id_string(...args) {
68
    let def = args[0]
69
    if (args.length > 1)
70
	def = {identifier: args[0], version: args[1], revision: args[2]};
71
    return !Array.isArray(def.version) ? def.identifier :
72
	`${def.identifier}-${version_string(def.version, def.revision)}`;
73
}
74
#EXPORT item_id_string
75

    
76
/* vers should be an array of comparable values. Return the greatest one. */
77
const max = vals => vals.reduce((v1, v2) => v1 > v2 ? v1 : v2);
78

    
79
/*
80
 * versioned_item should be a dict with keys being version strings and values
81
 * being definitions of the respective versions of a single resource/mapping.
82
 * Example:
83
 *     {
84
 *         "1": {
85
 *             version: [1]//,
86
 *             // more stuff
87
 *         },
88
 *         "1.1": {
89
 *             version: [1, 1]//,
90
 *             // more stuff
91
 *         }
92
 *      }
93
 *
94
 * Returns the definition with the highest version.
95
 */
96
function get_newest_version(versioned_item)
97
{
98
    const best_ver = max(Object.keys(versioned_item).map(parse_version));
99
    return versioned_item[version_string(best_ver)];
100
}
101
#EXPORT get_newest_version AS get_newest
102

    
103
/*
104
 * item is a definition of a resource or mapping. Yield all file references
105
 * (objects with `file` and `sha256` properties) this definition has.
106
 */
107
function* get_used_files(item)
108
{
109
    for (const file of item.source_copyright)
110
	yield file;
111

    
112
    if (item.type === "resource") {
113
	for (const file of item.scripts || [])
114
	    yield file;
115
    }
116
}
117
#EXPORT get_used_files AS get_files
118

    
119
/*
120
 * Function to parse URIs like:
121
 *     https://hydrilla.koszko.org/schemas/api_mapping_description-2.schema.json
122
 */
123
const name_base_re    = "([^/]*)";
124
const major_number_re = "([1-9][0-9]*)";
125
const minor_number_re = "(?:[1-9][0-9]*|0)";
126
const numbers_rest_re = `(?:\\.${minor_number_re})*`;
127
const version_re      = `(${major_number_re}${numbers_rest_re})`;
128
const schema_name_re  = `${name_base_re}-${version_re}\\.schema\\.json`;
129

    
130
const schema_name_regex = new RegExp(schema_name_re);
131

    
132
const schema_name_parts = ["full", "name_base", "version", "major"];
133

    
134
function parse_schema_uri(uri) {
135
    const match = schema_name_regex.exec(uri);
136
    if (!match)
137
	return match;
138

    
139
    const result = {};
140

    
141
    for (let i = 0; i < schema_name_parts.length; i++)
142
	result[schema_name_parts[i]] = match[i];
143

    
144
    return result
145
}
146
#EXPORT parse_schema_uri
147

    
148
/* Extract the number that indicates entity's compatibility mode. */
149
function get_schema_major_version(instance) {
150
    return parseInt(parse_schema_uri(instance.$schema).major);
151
}
152
#EXPORT get_schema_major_version
153

    
154
#IF NEVER
155

    
156
/*
157
 * Note: the functions below were overeagerly written and are not used now but
158
 * might prove useful to once we add more functionalities and are hence kept...
159
 */
160

    
161
/*
162
 * Clone recursively all objects. Leave other items (arrays, strings) untouched.
163
 */
164
function deep_object_copy(object)
165
{
166
    const orig = {object};
167
    const result = {};
168
    const to_copy = [[orig, {}]];
169

    
170
    while (to_copy.length > 0) {
171
	const [object, copy] = to_copy.pop();
172

    
173
	for (const [key, value] of Object.entries(object)) {
174
	    copy[key] = value;
175

    
176
	    if (typeof value === "object" && !Array.isArray(value)) {
177
		const value_copy = {};
178
		to_copy.push([value, value_copy]);
179
		copy[key] = value_copy;
180
	    }
181
	}
182
    }
183

    
184
    return result.orig;
185
}
186

    
187
/* helper function for normalize_version() */
188
const version_reductor = (acc, n) => [...(n || acc.length ? [n] : []), ...acc];
189
/*
190
 * ver is an array of integers. Strip right-most zeroes from ver.
191
 *
192
 * Returns a *new* array. Doesn't modify its argument.
193
 */
194
const normalize_version = ver => ver.reduceRight(version_reductor, []);
195

    
196
#ENDIF
(3-3/11)