-
Notifications
You must be signed in to change notification settings - Fork 518
/
index.ts
138 lines (125 loc) · 4.47 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
///<amd-module name="@bazel/concatjs"/>
/*
* Concat all JS files before serving.
*/
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import * as process from 'process';
import {createInterface} from 'readline';
///<reference types="lib.dom"/>
/**
* Return SHA1 of data buffer.
*/
function sha1(data) {
const hash = crypto.createHash('sha1');
hash.update(data);
return hash.digest('hex');
}
/**
* Entry-point for the Karma plugin.
*/
function initConcatJs(logger, emitter, basePath, hostname, port) {
const log = logger.create('framework.concat_js');
// Create a tmp file for the concat bundle, rely on Bazel to clean the TMPDIR
const tmpFile =
path.join(process.env['TEST_TMPDIR'], crypto.randomBytes(6).readUIntLE(0, 6).toString(36));
emitter.on('file_list_modified', files => {
const bundleFile = {
path: '/concatjs_bundle.js',
contentPath: tmpFile,
isUrl: false,
content: '',
encodings: {},
} as any;
// Preserve all non-JS that were there in the included list.
const included = files.included.filter(f => path.extname(f.originalPath) !== '.js');
const bundledFiles =
files.included.filter(f => path.extname(f.originalPath) === '.js').map((file) => {
const relativePath = path.relative(basePath, file.originalPath).replace(/\\/g, '/');
let content = file.content + `\n//# sourceURL=http://${hostname}:${port}/base/` +
relativePath + '\n';
return `
loadFile(
${JSON.stringify(relativePath)},
${JSON.stringify(content)});`;
});
// Execute each file by putting it in a <script> tag. This makes them create
// global variables, even with 'use strict'; (unlike eval).
bundleFile.content = `
(function() { // Hide local variables
// Use policy to support Trusted Types enforcement.
var policy = null;
if (window.trustedTypes) {
try {
policy = window.trustedTypes.createPolicy('bazel-karma', {
createScript: function(s) { return s; }
});
} catch (e) {
// In case the policy has been unexpectedly created before, log the error
// and fall back to the old behavior.
console.log(e);
}
}
// IE 8 and below do not support document.head.
var parent = document.getElementsByTagName('head')[0] ||
document.documentElement;
function loadFile(path, src) {
var trustedSrc = policy ? policy.createScript(src) : src;
try {
var script = document.createElement('script');
if ('textContent' in script) {
script.textContent = trustedSrc;
} else {
// This is for IE 8 and below.
script.text = trustedSrc;
}
parent.appendChild(script);
// Don't pollute the DOM with hundreds of <script> tags.
parent.removeChild(script);
} catch(err) {
window.__karma__ && window.__karma__.error(
'An error occurred while loading ' + path + ':\\n' +
(err.stack || err.message || err.toString()));
console.error('An error occurred while loading ' + path, err);
throw err;
}
}
${bundledFiles.join('')}
})();`;
bundleFile.sha = sha1(Buffer.from(bundleFile.content));
bundleFile.mtime = new Date();
included.unshift(bundleFile);
files.included = included;
files.served.push(bundleFile);
log.debug('Writing concatjs bundle to tmp file %s', bundleFile.contentPath);
fs.writeFileSync(bundleFile.contentPath, bundleFile.content);
});
}
(initConcatJs as any).$inject =
['logger', 'emitter', 'config.basePath', 'config.hostname', 'config.port'];
function watcher(fileList: {refresh: () => void}) {
// ibazel will write this string after a successful build
// We don't want to re-trigger tests if the compilation fails, so
// we should only listen for this event.
const IBAZEL_NOTIFY_BUILD_SUCCESS = 'IBAZEL_BUILD_COMPLETED SUCCESS';
// ibazel communicates with us via stdin
const rl = createInterface({input: process.stdin, terminal: false});
rl.on('line', (chunk: string) => {
if (chunk === IBAZEL_NOTIFY_BUILD_SUCCESS) {
fileList.refresh();
}
});
rl.on('close', () => {
// Give ibazel 5s to kill our process, otherwise do it ourselves
setTimeout(() => {
console.error('ibazel failed to stop karma after 5s; probably a bug');
process.exit(1);
}, 5000);
});
}
(watcher as any).$inject = ['fileList'];
module.exports = {
'framework:concat_js': ['factory', initConcatJs],
'watcher': ['value', watcher],
};