• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Lumieducation / H5P-Nodejs-library / 4b635272-6b60-47b1-8b72-b71bf64c97d2

11 Aug 2025 10:33PM UTC coverage: 70.014% (-0.07%) from 70.087%
4b635272-6b60-47b1-8b72-b71bf64c97d2

push

circleci

web-flow
chore(deps): update typescript-eslint monorepo to v8.39.1 (#4236)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

2571 of 4230 branches covered (60.78%)

Branch coverage included in aggregate %.

6075 of 8119 relevant lines covered (74.82%)

6609.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.52
/packages/h5p-server/src/ContentFileScanner.ts
1
import { ContentScanner } from './ContentScanner';
32✔
2
import Logger from './helpers/Logger';
32✔
3
import LibraryManager from './LibraryManager';
4
import { ILibraryName, ISemanticsEntry } from './types';
5

6
const log = new Logger('ContentFileScanner');
32✔
7

8
/**
9
 * Describes a reference to a file that is embedded inside the content.
10
 */
11
export interface IFileReference {
12
    /**
13
     * Information about where the file reference was found
14
     */
15
    context: {
16
        /**
17
         * The path of the object **inside the params tree**. You can use this
18
         * path to later modify the params, if needed.
19
         */
20
        jsonPath: string;
21
        /**
22
         * The raw parameters of the object.
23
         */
24
        params: any;
25
        /**
26
         * The semantic structure of the object (as defined in semantics.json).
27
         *
28
         * Can be null or undefined if there is no semantic structure for the
29
         * element (happens if the file can be found somewhere that is not
30
         * described by the semantics)
31
         */
32
        semantics?: ISemanticsEntry;
33
    };
34
    /**
35
     * The path of the file **inside the H5P content directory** as can be used
36
     * to reference it in ContentManager (without any suffixes like #tmp).
37
     */
38
    filePath: string;
39
    /**
40
     * The mime type specified in the params
41
     */
42
    mimeType?: string;
43
    /**
44
     * If true, the file was marked as temporary (by the #tmp suffix). The
45
     * suffix is **not included** in filePath
46
     */
47
    temporary: boolean;
48
}
49

50
/**
51
 * Scans the content parameters (=content.json) of a piece of content and
52
 * returns a list of references to file that are embedded inside the content.
53
 */
54
export class ContentFileScanner extends ContentScanner {
32✔
55
    constructor(libraryManager: LibraryManager) {
56
        super(libraryManager);
354✔
57
        log.info('initialize');
354✔
58
    }
59

60
    /**
61
     * Used to differentiate between local files and URLs.
62
     */
63
    private static urlRegExp: RegExp = /^https?:\/\//;
32✔
64

65
    /**
66
     * Loads the specified content from the ContentManager and scans its
67
     * parameters (= content.json) for references to local files (= audio,
68
     * video, images, generic files).
69
     * @param contentId the content to scan
70
     * @param user the user who wants to access the file
71
     * @returns a list of local files
72
     */
73
    public async scanForFiles(
74
        mainParams: any,
75
        mainLibraryName: ILibraryName
76
    ): Promise<IFileReference[]> {
77
        const results: IFileReference[] = [];
546✔
78
        await this.scanContent(
546✔
79
            mainParams,
80
            mainLibraryName,
81
            (semantics, params, jsonPath) => {
82
                log.debug(
164,984✔
83
                    `Checking entry ${jsonPath} (type ${semantics.type})`
84
                );
85
                switch (semantics.type) {
164,984✔
86
                    case 'file':
87
                    case 'image': {
88
                        log.debug(`found ${semantics.type} element`);
1,208✔
89
                        const element = this.pushIfDefined(
1,208✔
90
                            results,
91
                            this.checkFileElement(semantics, params, jsonPath)
92
                        );
93
                        if (element) {
1,208✔
94
                            log.debug(
1,208✔
95
                                `Found file is a reference to ${element.filePath}`
96
                            );
97
                        }
98
                        if (params.originalImage) {
1,208✔
99
                            const originalImageElement = this.pushIfDefined(
32✔
100
                                results,
101
                                this.checkFileElement(
102
                                    null,
103
                                    params.originalImage,
104
                                    `${jsonPath}.originalImage`
105
                                )
106
                            );
107
                            if (originalImageElement) {
32✔
108
                                log.debug(
32✔
109
                                    `Found file is a reference to ${originalImageElement.filePath}`
110
                                );
111
                            }
112
                        }
113
                        return true; // returning true aborts further recursion
1,208✔
114
                    }
115
                    case 'video':
116
                    case 'audio':
117
                        if (Array.isArray(params)) {
176✔
118
                            for (
176✔
119
                                let index = 0;
176✔
120
                                index < params.length;
121
                                index += 1
122
                            ) {
123
                                const arrayElement = this.pushIfDefined(
176✔
124
                                    results,
125
                                    this.checkFileElement(
126
                                        null,
127
                                        params[index],
128
                                        `${jsonPath}[${index}]`
129
                                    )
130
                                );
131
                                if (arrayElement) {
176✔
132
                                    log.debug(
104✔
133
                                        `Found file is a reference to ${arrayElement.filePath}`
134
                                    );
135
                                }
136
                            }
137
                        }
138
                        return true; // returning true aborts further recursion
176✔
139
                    default:
140
                        return false;
163,600✔
141
                }
142
            }
143
        );
144
        return results;
546✔
145
    }
146

147
    /**
148
     * Checks if an element in the parameter tree contains a valid reference to
149
     * a local file and removes temporary markers.
150
     * @param semantics The semantic structure of the element to check
151
     * @param params the parameter object of the element to check
152
     * @param jsonPath the JSONPath at which the element can be found in the
153
     * parameter object
154
     * @returns an object with information about the file reference; undefined
155
     * if the file reference is invalid
156
     */
157
    private checkFileElement(
158
        semantics: ISemanticsEntry,
159
        params: any,
160
        jsonPath: string
161
    ): IFileReference {
162
        if (!params.path) {
1,416!
163
            // Path shouldn't be empty, but we simply ignore the entry in this
164
            // case.
165
            return undefined;
×
166
        }
167
        if (ContentFileScanner.urlRegExp.test(params.path)) {
1,416✔
168
            // If the file is a reference to a URL, we don't return it.
169
            return undefined;
72✔
170
        }
171

172
        let temporary = false;
1,344✔
173
        let cleanFileReferencePath = params.path;
1,344✔
174
        if (params.path.endsWith('#tmp')) {
1,344✔
175
            // files marked as temporary will be identified as such
176
            temporary = true;
362✔
177
            cleanFileReferencePath = params.path.substr(
362✔
178
                0,
179
                params.path.length - 4
180
            );
181
        }
182

183
        return {
1,344✔
184
            context: { semantics, params, jsonPath },
185
            filePath: cleanFileReferencePath,
186
            mimeType: params.mime,
187
            temporary
188
        };
189
    }
190

191
    /**
192
     * Helper function that pushes an item to an array if the item is defined.
193
     * @param array the array to push to
194
     * @param item the item to push
195
     * @returns the item (if defined); otherwise undefined
196
     */
197
    private pushIfDefined<T>(array: T[], item: T): T {
198
        if (item !== undefined) {
1,416✔
199
            array.push(item);
1,344✔
200
            return item;
1,344✔
201
        }
202
        return undefined;
72✔
203
    }
204
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc