File : LinkBuilder.js

1
/*
2
Copyright - 2021 - wwwouaiebe - Contact: https://www.ouaie.be/
3
4
This  program is free software;
5
you can redistribute it and/or modify it under the terms of the
6
GNU General Public License as published by the Free Software Foundation;
7
either version 3 of the License, or any later version.
8
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
GNU General Public License for more details.
13
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17
*/
18
/*
19
Changes:
20
    - v1.0.0:
21
        - created
22
    - v1.1.0:
23
        - Issue ♯3 : String.substr ( ) is deprecated... Replace...
24
    - v1.2.1:
25
        - Issue ♯5 : Sources files are not sorted correctly in nav part of the html pages
26
Doc reviewed 20211111
27
*/
28
/* ------------------------------------------------------------------------------------------------------------------------- */
29
30
import { marked } from 'marked';
31
32
/* ------------------------------------------------------------------------------------------------------------------------- */
33
/**
34
Store all the links  created from the source document and get the links completed with the path for others classes
35
*/
36
/* ------------------------------------------------------------------------------------------------------------------------- */
37
38
class LinkBuilder {
39
40
    /**
41
    A cache for the sources links
42
    @type {Array.<Array.<String>>}
43
    */
44
45
    #sourcesLinksCache;
46
47
    /**
48
    The links to the sources  files
49
    @type {Map.<String>}
50
    */
51
52
    #sourcesLinks;
53
54
    /**
55
    A cache for the classes links
56
    @type {Array.<Array.<String>>}
57
    */
58
59
    #classesLinksCache;
60
61
    /**
62
    The links to the classes  files
63
    @type {Map.<String>}
64
    */
65
66
    #classesLinks;
67
68
    /**
69
    A cache for the variables links
70
    @type {Array.<Array.<String>>}
71
    */
72
73
    #variablesLinksCache;
74
75
    /**
76
    The links to the variables file and the variables in the file
77
    @type {Map.<String>}
78
    */
79
80
    #variablesLinks;
81
82
    /**
83
    The links to the mdn documentation
84
    @type {Object}
85
    */
86
87
    #mdnLinks = Object.freeze (
88
        {
89
90
            // Global objects
91
            Array : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array',
92
            ArrayBuffer : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer',
93
            Boolean : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean',
94
            Error : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error',
95
            File : 'https://developer.mozilla.org/en-US/docs/Web/API/File',
96
            Function : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function',
97
            Map : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map',
98
            Number : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number',
99
            Object : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object',
100
            Promise : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise',
101
            RegExp : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp',
102
            String : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String',
103
            Uint8Array : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array',
104
105
            // Statements
106
            Class : 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class',
107
108
            // API
109
            CryptoKey : 'https://developer.mozilla.org/en-US/docs/Web/API/CryptoKey',
110
            Event : 'https://developer.mozilla.org/en-US/docs/Web/API/Event',
111
            GeolocationPosition : 'https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPosition',
112
            GeolocationPositionError : 'https://developer.mozilla.org/en-US/docs/Web/API/GeolocationPositionError',
113
            IDBFactory : 'https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory',
114
            HTMLCollection : 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection',
115
            HTMLElement : 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement',
116
            Node : 'https://developer.mozilla.org/en-US/docs/Web/API/Node',
117
            NodeList : 'https://developer.mozilla.org/en-US/docs/Web/API/NodeList',
118
            SVGElement : 'https://developer.mozilla.org/en-US/docs/Web/API/SVGElement',
119
            Touch : 'https://developer.mozilla.org/en-US/docs/Web/API/Touch',
120
            TouchList : 'https://developer.mozilla.org/en-US/docs/Web/API/TouchList',
121
            XMLDocument : 'https://developer.mozilla.org/en-US/docs/Web/API/XMLDocument',
122
123
            // Others
124
            LeafletObject : 'https://leafletjs.com/reference.html',
125
            OsmElement : 'https://wiki.openstreetmap.org/wiki/Overpass_API/Overpass_QL',
126
            JsonObject : 'https://www.json.org/json-en.html'
127
        }
128
    );
129
130
    /**
131
    The constructor
132
    */
133
134
    constructor ( ) {
135
        Object.freeze ( this );
136
        this.#sourcesLinks = new Map ( );
137
        this.#classesLinks = new Map ( );
138
        this.#variablesLinks = new Map ( );
139
    }
140
141
    /**
142
    Get the html link to a class file
143
    @param {String} className The name of the class for witch the link must be created
144
    @param {String} rootPath The path between the file where the link will be inserted and theConfig.destDir
145
    ( something like '../../../', depending of the folders tree )
146
    @return {String} An html string with the link or the className when the link is not found
147
    */
148
149
    getClassLink ( className, rootPath ) {
150
        const classLink = this.#classesLinks.get ( className );
151
        return classLink ? `<a href="${rootPath + classLink}">${className}</a>` : className;
152
    }
153
154
    /**
155
    Store a link to a class file
156
    @param {ClassDoc} classDoc the doc with the class documentation
157
    */
158
159
    setClassLink ( classDoc ) {
160
        this.#classesLinks.set (
161
            classDoc.name,
162
            classDoc.file.substring ( 0, classDoc.file.lastIndexOf ( '/' ) + 1 ) + classDoc.name + '.html'
163
        );
164
    }
165
166
    /**
167
    Get all the classes links. Each subAray contains the class name and the class link.
168
    @type {Array.<Array.<String>>}
169
    */
170
171
    get classesLinks ( ) {
172
        if ( ! this.#classesLinksCache ) {
173
174
            // Create the cache if not exists
175
            this.#classesLinksCache = this.#classesLinksCache ?? Array.from ( this.#classesLinks ).sort (
176
                ( first, second ) => first [ 0 ] .localeCompare ( second [ 0 ] )
177
            );
178
        }
179
180
        return this.#classesLinksCache;
181
    }
182
183
    /**
184
    Get a link to a source file
185
    @param {VariableDoc|MethodOrPropertyDoc|VariableDoc} doc The doc for witch the link to the source file must be created.
186
    @return {?String} The link to the source file
187
    */
188
189
    getSourceLink ( doc ) {
190
        let sourceLink = this.#sourcesLinks.get ( doc.file );
191
        if ( sourceLink ) {
192
            // eslint-disable-next-line no-magic-numbers
193
            return doc.rootPath + sourceLink + '#L' + String ( doc.line ).padStart ( 5, '_' );
194
        }
195
        return null;
196
    }
197
198
    /**
199
    Store a link to a source file
200
    @param {String} fileName The file name
201
    @param {String} path The path since theConfig.destDir, included file name
202
    */
203
204
    setSourceLink ( fileName, path ) {
205
        this.#sourcesLinks.set ( fileName, path );
206
    }
207
208
    /**
209
    Get all the sources links. Each subAray contains the source file name and the path
210
    between theConfig.destDir  and the source file, included file name
211
    @type {Array.<Array.<String>>}
212
    */
213
214
    get sourcesLinks ( ) {
215
        if ( ! this.#sourcesLinksCache ) {
216
            this.#sourcesLinksCache = Array.from ( this.#sourcesLinks ).sort (
217
                ( first, second ) => {
218
                    const firstPath = first [ 0 ].substring ( 0, first [ 0 ].lastIndexOf ( '/' ) );
219
                    const firstFile = first [ 0 ].substring ( first [ 0 ].lastIndexOf ( '/' ) + 1 );
220
                    const secondPath = second [ 0 ].substring ( 0, second [ 0 ].lastIndexOf ( '/' ) );
221
                    const secondFile = second [ 0 ].substring ( second [ 0 ].lastIndexOf ( '/' ) + 1 );
222
                    const pathCompare = firstPath.localeCompare ( secondPath );
223
                    if ( 0 === pathCompare ) {
224
                        return firstFile.localeCompare ( secondFile );
225
                    }
226
                    return pathCompare;
227
                }
228
            );
229
        }
230
        return this.#sourcesLinksCache;
231
    }
232
233
    /**
234
    Store a link to a variable in the variables.html file
235
    @param {VariableDoc} variableDoc the doc with the variable documentation
236
    */
237
238
    setVariableLink ( variableDoc ) {
239
        this.#variablesLinks.set (
240
            variableDoc.name,
241
            `variables.html#${variableDoc.name}`
242
        );
243
    }
244
245
    /**
246
    Get all the variables links. Each subAray contains the variable name and the variable link.
247
    @type {Array.<Array.<String>>}
248
    */
249
250
    get variablesLinks ( ) {
251
        if ( ! this.#variablesLinksCache ) {
252
            this.#variablesLinksCache = Array.from ( this.#variablesLinks ).sort (
253
                ( first, second ) => first [ 0 ] .localeCompare ( second [ 0 ] )
254
            );
255
        }
256
        return this.#variablesLinksCache;
257
    }
258
259
    /**
260
    Get the link to a type
261
    @param {String} type The type for witch the link must be created. Must be a single word
262
    @param {String} rootPath The path between the file where the link will be inserted and theConfig.destDir
263
    ( something like '../../../', depending of the folders tree )
264
    @return {String} The link to the type. We search first in the classes links, then in the mdn links. If nothing
265
    found, the type without html link is returned.
266
    */
267
268
    #getTypeLink ( type, rootPath ) {
269
        if ( 'constructor' === type ) {
270
            return type;
271
        }
272
        const classLink = this.#classesLinks.get ( type );
273
        if ( classLink ) {
274
            return `<a href="${rootPath + classLink}">${type}</a>`;
275
        }
276
        const mdnLink = this.#mdnLinks [ type ];
277
        if ( mdnLink ) {
278
            return `<a href="${mdnLink}">${type}</a>`;
279
        }
280
        const variableLink = this.#variablesLinks.get ( type );
281
        if ( variableLink ) {
282
            return `<a href="${variableLink}">${type}</a>`;
283
        }
284
        return type;
285
    }
286
287
    /**
288
    Verify that a given type is a known type ( = present in the @classesLinks map
289
    or the mdnLinks object
290
    @param {String} type The type to verify
291
    @return {Boolean} True when the type is known
292
    */
293
294
    isKnownType ( type ) {
295
        return Boolean ( this.#classesLinks.get ( type ) || this.#mdnLinks [ type ] );
296
    }
297
298
    /**
299
    Get the links to a type
300
    @param {String} type The types for witch the link must be created. Can be multiple word
301
    @param {String} rootPath The path between the file where the link will be inserted and theConfig.destDir
302
    ( something like '../../../', depending of the folders tree )
303
    @return {String} The html links to the types. We search first in the classes links, then in the mdn links. If nothing
304
    found, the types without html link is returned.
305
    */
306
307
    getTypeLinks ( type, rootPath ) {
308
        if ( ! type ) {
309
            return 'null';
310
        }
311
        let returnType = '';
312
        type.split ( ' ' ).forEach (
313
            tmpType => returnType += this.#getTypeLink ( tmpType, rootPath ) + ' '
314
        );
315
316
        return returnType.trimEnd ( );
317
    }
318
319
    /**
320
    Add links to a description
321
    @param {String} desc The description to complete with links
322
    @param {String} rootPath The path between the file where the link will be inserted and theConfig.destDir
323
    ( something like '../../../', depending of the folders tree )
324
    @return {String} The description completed with html links
325
    */
326
327
    getDescLink ( desc, rootPath ) {
328
        let returnDesc = '';
329
        desc.split ( ' ' ).forEach (
330
            word => returnDesc += this.#getTypeLink ( word, rootPath ) + ' '
331
        );
332
        return marked.parse ( returnDesc.trimEnd ( ) );
333
    }
334
}
335
336
/**
337
The one and only one instance of LinkBuilder class
338
@type {LinkBuilder}
339
*/
340
341
const theLinkBuilder = new LinkBuilder ( );
342
343
export default theLinkBuilder;
344
345
/* --- End of file --------------------------------------------------------------------------------------------------------- */
346