1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.getKeys = void 0;
|
4 | class EnvRec extends Array {
|
5 | constructor(parent, namespace) {
|
6 | super();
|
7 | this._parent = parent;
|
8 | this._children = [];
|
9 | if (this._parent) {
|
10 | this._parent._children.push(this);
|
11 | }
|
12 | this._namespace = namespace;
|
13 | this._byType = {};
|
14 | this._byLocation = {};
|
15 | this._byProductionName = {};
|
16 | this._byAoid = {};
|
17 | this._keys = new Set();
|
18 | }
|
19 |
|
20 | push(...items) {
|
21 | for (const item of items) {
|
22 | pushKey(this._byType, item.type, item);
|
23 | pushKey(this._byLocation, item.location, item);
|
24 | if (item.type === 'clause' && item.aoid) {
|
25 | const op = {
|
26 | type: 'op',
|
27 | aoid: item.aoid,
|
28 | refId: item.id,
|
29 | location: item.location,
|
30 | referencingIds: [],
|
31 | };
|
32 | this.push(op);
|
33 | }
|
34 | if (item.type === 'op') {
|
35 | this._byAoid[item.aoid] = item;
|
36 | this._keys.add(item.aoid);
|
37 | }
|
38 | if (item.type === 'production') {
|
39 | this._byProductionName[item.name] = item;
|
40 | }
|
41 | if (item.type === 'term') {
|
42 | for (const key of getKeys(item)) {
|
43 | this._keys.add(key);
|
44 | }
|
45 | }
|
46 | }
|
47 | return super.push(...items);
|
48 | }
|
49 | }
|
50 |
|
51 | Object.defineProperty(EnvRec, Symbol.species, { value: Array });
|
52 |
|
53 | class Biblio {
|
54 | constructor(location) {
|
55 | this._byId = {};
|
56 | this._location = location;
|
57 | this._root = new EnvRec(undefined, 'global');
|
58 | this._nsToEnvRec = { global: this._root };
|
59 | this.createNamespace(location, 'global');
|
60 | }
|
61 | byId(id) {
|
62 | return this._byId[id];
|
63 | }
|
64 | byNamespace(ns) {
|
65 | const env = this._nsToEnvRec[ns];
|
66 | if (!env) {
|
67 | throw new Error('Namespace ' + ns + ' not found');
|
68 | }
|
69 | return env;
|
70 | }
|
71 | byProductionName(name, ns) {
|
72 | ns = ns || this._location;
|
73 | return this.lookup(ns, env => env._byProductionName[name]);
|
74 | }
|
75 | byAoid(aoid, ns) {
|
76 | ns = ns || this._location;
|
77 | return this.lookup(ns, env => env._byAoid[aoid]);
|
78 | }
|
79 | getDefinedWords(ns) {
|
80 | const result = Object.create(null);
|
81 | for (const type of ['term', 'op']) {
|
82 |
|
83 |
|
84 | const seen = new Set();
|
85 | let current = this._nsToEnvRec[ns];
|
86 | while (current) {
|
87 | const entries = current._byType[type] || [];
|
88 | for (const entry of entries) {
|
89 | let keys;
|
90 | if (type === 'term') {
|
91 | if (entry.term === 'type') {
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | continue;
|
97 | }
|
98 | keys = getKeys(entry).flatMap(key => {
|
99 | if (/^[a-z]/.test(key)) {
|
100 |
|
101 | return [key, key[0].toUpperCase() + key.slice(1)];
|
102 | }
|
103 | return key;
|
104 | });
|
105 | }
|
106 | else {
|
107 | keys = [entry.aoid];
|
108 | }
|
109 | for (const key of keys) {
|
110 | if (!seen.has(key)) {
|
111 | seen.add(key);
|
112 | result[key] = entry;
|
113 | }
|
114 | }
|
115 | }
|
116 | current = current._parent;
|
117 | }
|
118 | }
|
119 | return result;
|
120 | }
|
121 | lookup(ns, cb) {
|
122 | let env = this._nsToEnvRec[ns];
|
123 | if (!env) {
|
124 | throw new Error('Namespace ' + ns + ' not found');
|
125 | }
|
126 | while (env) {
|
127 | const result = cb(env);
|
128 | if (result) {
|
129 | return result;
|
130 | }
|
131 | env = env._parent;
|
132 | }
|
133 | return undefined;
|
134 | }
|
135 | add(entry, ns) {
|
136 | ns = ns || this._location;
|
137 | const env = this._nsToEnvRec[ns];
|
138 | entry.namespace = ns;
|
139 |
|
140 | entry.location = entry.location || '';
|
141 |
|
142 | entry.referencingIds = entry.referencingIds || [];
|
143 | env.push(entry);
|
144 | if (entry.id) {
|
145 | if ({}.hasOwnProperty.call(this, entry.id)) {
|
146 | throw new Error('Duplicate biblio entry ' + JSON.stringify(entry.id) + '.');
|
147 | }
|
148 | this._byId[entry.id] = entry;
|
149 | }
|
150 | }
|
151 | createNamespace(ns, parent) {
|
152 | const existingNs = this._nsToEnvRec[ns];
|
153 | if (existingNs) {
|
154 | if (existingNs._parent._namespace === parent) {
|
155 | return;
|
156 | }
|
157 | else {
|
158 | throw new Error('Namespace ' + ns + ' already in use.');
|
159 | }
|
160 | }
|
161 | if (!parent) {
|
162 | throw new Error('Cannot create namespace without parent');
|
163 | }
|
164 | const parentEnv = this._nsToEnvRec[parent];
|
165 | if (!parentEnv) {
|
166 | throw new Error('Cannot find namespace with name ' + parent);
|
167 | }
|
168 | if (!ns) {
|
169 | throw new Error('Cannot create namespace without a name');
|
170 | }
|
171 | const env = new EnvRec(parentEnv, ns);
|
172 | this._nsToEnvRec[ns] = env;
|
173 | }
|
174 | addExternalBiblio(biblio) {
|
175 | Object.keys(biblio).forEach(site => {
|
176 | biblio[site].forEach(entry => {
|
177 | entry.location = site;
|
178 | this.add(entry, 'global');
|
179 | });
|
180 | });
|
181 | }
|
182 | keysForNamespace(ns) {
|
183 | return this._nsToEnvRec[ns]._keys;
|
184 | }
|
185 | toJSON() {
|
186 | let root = [];
|
187 | function addEnv(env) {
|
188 | root = root.concat(env);
|
189 | env._children.forEach(addEnv);
|
190 | }
|
191 | addEnv(this.byNamespace(this._location));
|
192 | return root;
|
193 | }
|
194 | dump() {
|
195 | dumpEnv(this._root);
|
196 | }
|
197 | }
|
198 | exports.default = Biblio;
|
199 | function dumpEnv(env) {
|
200 | console.log('## ' + env._namespace);
|
201 | console.log(env.map(entry => JSON.stringify(entry)).join(', '));
|
202 | env._children.forEach(child => {
|
203 | dumpEnv(child);
|
204 | });
|
205 | }
|
206 | function pushKey(arr, key, value) {
|
207 | if (arr[key] === undefined) {
|
208 | arr[key] = [];
|
209 | }
|
210 | arr[key].push(value);
|
211 | }
|
212 | function getKeys(entry) {
|
213 | return [entry.term, ...(entry.variants || [])].map(v => v.replace(/\s+/g, ' '));
|
214 | }
|
215 | exports.getKeys = getKeys;
|