Skip to content

Commit deae870

Browse files
committed
Added files
1 parent c20abb3 commit deae870

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1990
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
**/.vscode-test
3+
**/out
4+
**/dist
5+
**/*.vsix

.vscodeignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.vscode/**
2+
.vscode-test/**
3+
node_modules/**
4+
.gitignore
5+
tsconfig.json
6+
tslint.json

README.md

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# VSCode Sourcemap Helper
2+
3+
Monorepo for the VSCode Sourcemap Helper extension.
4+
5+
## Getting started
6+
7+
```bash
8+
# Install dependencies for all projects
9+
npm install
10+
11+
# Build all projects
12+
npm run build
13+
14+
# Run tests
15+
npm run test
16+
17+
# Bundle project with dependencies to single file js
18+
npm run bundle
19+
20+
# Create extension VSIX from bundle
21+
npm run vsce
22+
```
23+
24+
The extension is saved in `packages/vscode-sourcemap-helper/sourcemap-helper-(VERSION).vsix`
25+
26+
Projects:
27+
28+
- [vscode-sourcemap-helper](./packages/vscode-sourcemap-helper/README.md)
29+
- [vscode-sourcemap-helper-test](./packages/vscode-sourcemap-helper-test/)
30+
31+
## Shout outs
32+
33+
Based on on https://github.com/vladimir-kotikov/vscode-sourcemaps-navigator by Vladimir Kotikov.

package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "root",
3+
"workspaces": [
4+
"packages/vscode-sourcemap-helper",
5+
"packages/vscode-sourcemap-helper-test"
6+
],
7+
"scripts": {
8+
"build": "npm run build --workspaces",
9+
"build-all": "npm run build --workspaces",
10+
"dev": "npm run dev --w vscode-sourcemap-helper",
11+
"test": "npm run test --w packages/vscode-sourcemap-helper-test",
12+
"vsce": "npm run vsce --w packages/vscode-sourcemap-helper",
13+
"bundle": "npm run bundle --w packages/vscode-sourcemap-helper"
14+
}
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const { defineConfig } = require('@vscode/test-cli');
2+
3+
module.exports = defineConfig({
4+
files: 'out/**/*.test.js',
5+
workspaceFolder: 'test-workspace', // The path to a workspace to open during tests.
6+
extensionDevelopmentPath: '../vscode-sourcemap-helper',
7+
mocha: {
8+
9+
}
10+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "sourcemap-helper-test",
3+
"version": "0.0.0",
4+
"publisher": "andersnm",
5+
"private": true,
6+
"engines": {
7+
"vscode": "^1.90.0"
8+
},
9+
"main": "./out/src/extension",
10+
"scripts": {
11+
"build": "tsc -p ./",
12+
"test": "vscode-test",
13+
"testold": "node ./node_modules/vscode/bin/test"
14+
},
15+
"devDependencies": {
16+
"@types/mocha": "^10.0.6",
17+
"@types/node": "^20.12.12",
18+
"@types/node-fetch": "^2.6.11",
19+
"@types/vscode": "1.90.0",
20+
"@vscode/test-cli": "^0.0.9",
21+
"@vscode/test-electron": "^2.4.0",
22+
"@vscode/vsce": "^2.26.1",
23+
"tslint": "^4.4.2",
24+
"typescript": "5.4.5",
25+
"vscode-test": "^1.6.1"
26+
},
27+
"dependencies": {
28+
"node-fetch": "^2.7.0",
29+
"source-map": "^0.7.4",
30+
"vscode-sourcemap-helper": "file:../vscode-sourcemap-helper"
31+
}
32+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import * as assert from 'assert';
2+
import * as vscode from 'vscode';
3+
4+
import { SourceMapStore, encodeSourceMapSourceUri, OutputChannelLogger } from 'vscode-sourcemap-helper';
5+
// import { SourceMapStore } from '../src/SourceMapStore';
6+
import { createServer, stopServer } from './server';
7+
// import { encodeSourceMapSourceUri } from '../src/UriHelper';
8+
import { SourceMapConsumer } from 'source-map';
9+
// import { OutputChannelLogger } from '../src/Logger';
10+
11+
export async function closeFileIfOpen(file: vscode.Uri) : Promise<void> {
12+
const tabs: vscode.Tab[] = vscode.window.tabGroups.all.map(tg => tg.tabs).flat();
13+
const index = tabs.findIndex(tab => tab.input instanceof vscode.TabInputText && tab.input.uri.path === file.path);
14+
if (index !== -1) {
15+
await vscode.window.tabGroups.close(tabs[index]);
16+
}
17+
}
18+
19+
function getSourceMapConsumerSources(sourceMap: SourceMapConsumer) {
20+
const sources = [];
21+
sourceMap.eachMapping(item => {
22+
if (sources.includes(item.source)) {
23+
return;
24+
}
25+
26+
sources.push(item.source);
27+
});
28+
29+
return sources;
30+
}
31+
32+
async function testOpenSourceFilesFor(generatedFileWithMap: vscode.Uri) {
33+
const document = await vscode.workspace.openTextDocument(generatedFileWithMap);
34+
const outputChannel = vscode.window.createOutputChannel('Source maps');
35+
const logger = new OutputChannelLogger(outputChannel);
36+
const sms = new SourceMapStore(logger);
37+
const mapping = await sms.getForDocument(document);
38+
const sources = getSourceMapConsumerSources(mapping.sourceMap);
39+
40+
for (let source of sources) {
41+
const sourceUri = encodeSourceMapSourceUri(mapping.sourceMapUri, source);
42+
43+
await assert.doesNotReject(async () => {
44+
const sourceDocument = await vscode.workspace.openTextDocument(sourceUri);
45+
const sourceEditor = await vscode.window.showTextDocument(sourceDocument);
46+
47+
await closeFileIfOpen(sourceUri);
48+
});
49+
}
50+
51+
}
52+
53+
suite("SourceMapStore", () => {
54+
55+
suiteSetup(async () => {
56+
// wait for activation
57+
58+
// perhaps, can call activate from here? if it checks the singleton
59+
60+
// await extensionActivated;
61+
});
62+
63+
test("flat: Open source files", async () => {
64+
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
65+
const minJsUri = vscode.Uri.joinPath(workspaceUri, "flat/min.js")
66+
await testOpenSourceFilesFor(minJsUri);
67+
// assert.equal(workspaceUri.toString(true) + "/flat", mapping.sourceMapBaseUri.toString(true));
68+
});
69+
70+
test("flat_no_sourceRoot: Open source files", async () => {
71+
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
72+
const minJsUri = vscode.Uri.joinPath(workspaceUri, "flat_no_sourceRoot/min.js")
73+
await testOpenSourceFilesFor(minJsUri);
74+
// assert.equal(workspaceUri.toString(true) + "/flat", mapping.sourceMapBaseUri.toString(true));
75+
});
76+
77+
test("with_src_out: Open source files", async () => {
78+
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
79+
const minJsUri = vscode.Uri.joinPath(workspaceUri, "with_src_out/out/min.js")
80+
await testOpenSourceFilesFor(minJsUri);
81+
// assert.equal(workspaceUri.toString(true) + "/flat", mapping.sourceMapBaseUri.toString(true));
82+
});
83+
84+
test("with_src_out_no_sourceRoot: Open source files", async () => {
85+
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
86+
const minJsUri = vscode.Uri.joinPath(workspaceUri, "with_src_out_no_sourceRoot/out/min.js")
87+
await testOpenSourceFilesFor(minJsUri);
88+
});
89+
90+
test("inline: Open source files", async () => {
91+
const workspaceUri = vscode.workspace.workspaceFolders[0].uri;
92+
const minJsUri = vscode.Uri.joinPath(workspaceUri, "inline/min.js")
93+
await testOpenSourceFilesFor(minJsUri);
94+
});
95+
96+
test("flat via http", async () => {
97+
const httpRootUri = vscode.workspace.workspaceFolders[0].uri;
98+
const server = await createServer("localhost", 8809, httpRootUri.fsPath);
99+
100+
const minJsUri = vscode.Uri.parse("sourcemap-http://localhost:8809/flat/min.js");
101+
// const minJsUri = encodeSourceMapSourceUri(vscode.Uri.parse("null:null"), vscode.Uri.parse("http://localhost:8809/flat/min.js"));
102+
await testOpenSourceFilesFor(minJsUri);
103+
104+
await stopServer(server);
105+
});
106+
107+
test("flat_no_sourceRoot via http", async () => {
108+
const httpRootUri = vscode.workspace.workspaceFolders[0].uri;
109+
const server = await createServer("localhost", 8809, httpRootUri.fsPath);
110+
111+
const minJsUri = vscode.Uri.parse("sourcemap-http://localhost:8809/flat_no_sourceRoot/min.js");
112+
// const minJsUri = encodeSourceMapSourceUri(vscode.Uri.parse("null:null"), vscode.Uri.parse("http://localhost:8809/flat_no_sourceRoot/min.js"));
113+
await testOpenSourceFilesFor(minJsUri);
114+
115+
await stopServer(server);
116+
});
117+
118+
test("remote via http", async () => {
119+
const httpRootUri = vscode.workspace.workspaceFolders[0].uri;
120+
const server = await createServer("localhost", 8809, httpRootUri.fsPath);
121+
122+
const minJsUri = vscode.Uri.parse("sourcemap-http://localhost:8809/remote/min.js");
123+
// const minJsUri = encodeSourceMapSourceUri(vscode.Uri.parse("null:null"), vscode.Uri.parse("http://localhost:8809/remote/min.js"));
124+
await testOpenSourceFilesFor(minJsUri);
125+
126+
await stopServer(server);
127+
});
128+
129+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
3+
//
4+
// This file is providing the test runner to use when running extension tests.
5+
// By default the test runner in use is Mocha based.
6+
//
7+
// You can provide your own test runner if you want to override it by exporting
8+
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
9+
// host can call to run the tests. The test runner is expected to use console.log
10+
// to report the results back to the caller. When the tests are finished, return
11+
// a possible error to the callback or null if none.
12+
13+
var testRunner = require('vscode/lib/testrunner');
14+
15+
// You can directly control Mocha options by uncommenting the following lines
16+
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
17+
testRunner.configure({
18+
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
19+
useColors: true // colored output from test results
20+
});
21+
22+
module.exports = testRunner;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// quick and dirty http server based on https://stackoverflow.com/a/29046869
2+
import * as fs from 'fs/promises';
3+
import * as http from 'http';
4+
import * as path from 'path';
5+
6+
async function serveStaticFile(request: http.IncomingMessage, response: http.ServerResponse, rootPath: string) {
7+
const filePath = path.join(rootPath, request.url)
8+
9+
console.log('HTTP server: ' + request.url + ", " + filePath);
10+
11+
const extname = path.extname(filePath);
12+
let contentType = 'text/html';
13+
switch (extname) {
14+
case '.js':
15+
contentType = 'text/javascript';
16+
break;
17+
case '.css':
18+
contentType = 'text/css';
19+
break;
20+
case '.json':
21+
case '.map':
22+
contentType = 'application/json';
23+
break;
24+
case '.png':
25+
contentType = 'image/png';
26+
break;
27+
case '.jpg':
28+
contentType = 'image/jpg';
29+
break;
30+
case '.wav':
31+
contentType = 'audio/wav';
32+
break;
33+
}
34+
35+
try {
36+
const content = await fs.readFile(filePath);
37+
response.writeHead(200, { 'Content-Type': contentType });
38+
response.end(content, 'utf-8');
39+
} catch (error) {
40+
response.writeHead(500);
41+
response.end('HTTP 500 Server error: ' + error.code + '\n');
42+
response.end();
43+
}
44+
};
45+
46+
export async function createServer(host, port, rootPath): Promise<http.Server> {
47+
48+
const requestListener = (request: http.IncomingMessage, response: http.ServerResponse) => {
49+
serveStaticFile(request, response, rootPath);
50+
};
51+
52+
const server = http.createServer(requestListener);
53+
54+
return new Promise<http.Server>((resolve, reject) => {
55+
const error = () => {
56+
server.off("listening", listening);
57+
server.off("error", error);
58+
reject();
59+
};
60+
61+
const listening = () => {
62+
console.log(`HTTP server is running on http://${host}:${port}`);
63+
server.off("listening", listening);
64+
server.off("error", error);
65+
resolve(server);
66+
};
67+
68+
server.on("error", error);
69+
server.on("listening", listening);
70+
71+
server.listen(port, host);
72+
});
73+
}
74+
75+
export async function stopServer (server: http.Server) {
76+
return new Promise<void>((resolve, reject) => {
77+
const close = (err: any) => {
78+
server.off("close", close);
79+
80+
if (err) {
81+
console.log(`HTTP server failed to stop ` + err.message);
82+
reject(err);
83+
return;
84+
}
85+
86+
console.log(`HTTP server stopped`);
87+
resolve();
88+
};
89+
90+
server.on("close", close);
91+
92+
server.close();
93+
server.closeAllConnections();
94+
});
95+
}

0 commit comments

Comments
 (0)