Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improved sourcemaps with relative paths and better relative handling for extern #5550

Merged
merged 22 commits into from
Jan 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions examples/tests/invalid/extern_above.test.w

This file was deleted.

4 changes: 4 additions & 0 deletions examples/tests/invalid/lib/extern_above.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Foo1 {
extern "../../valid/external_js.js" static getGreeting(name: str): str;
//^ must be a sub directory of the entrypoint
}
MarkMcCulloh marked this conversation as resolved.
Show resolved Hide resolved
40 changes: 27 additions & 13 deletions libs/wingc/src/jsify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use camino::{Utf8Path, Utf8PathBuf};
use const_format::formatcp;
use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use parcel_sourcemap::utils::make_relative_path;

use std::{borrow::Borrow, cell::RefCell, cmp::Ordering, collections::BTreeMap, vec};

Expand Down Expand Up @@ -269,7 +270,11 @@ impl<'a> JSifier<'a> {
let source_content = self.source_files.get_file(source_path.as_str()).unwrap();

let output_base = output.to_string();
let output_sourcemap = output.generate_sourcemap(source_path.as_str(), source_content, &preflight_file_name);
let output_sourcemap = output.generate_sourcemap(
&make_relative_path(self.out_dir.as_str(), source_path.as_str()),
source_content,
&preflight_file_name,
);

// Emit the file
match self
Expand Down Expand Up @@ -1300,22 +1305,30 @@ impl<'a> JSifier<'a> {
FunctionBody::Statements(scope) => self.jsify_scope_body(scope, ctx),
FunctionBody::External(extern_path) => {
let extern_path = Utf8Path::new(extern_path);
let entrypoint_dir = if self.compilation_init_path.is_file() {
let entrypoint_is_file = self.compilation_init_path.is_file();
let entrypoint_dir = if entrypoint_is_file {
self.compilation_init_path.parent().unwrap()
} else {
self.compilation_init_path
};

// extern_path should always be a sub directory of entrypoint_dir
let Ok(rel_path) = extern_path.strip_prefix(&entrypoint_dir) else {
report_diagnostic(Diagnostic {
message: format!("{extern_path} must be a sub directory of {entrypoint_dir}"),
annotations: vec![],
hints: vec![],
span: Some(func_def.span.clone()),
});
return CodeMaker::default();
};
if !entrypoint_is_file {
// We are possibly compiling a package, so we need to make sure all externs
// are actually contained in this directory to make sure it gets packaged

if !extern_path.starts_with(entrypoint_dir) {
report_diagnostic(Diagnostic {
message: format!("{extern_path} must be a sub directory of {entrypoint_dir}"),
annotations: vec![],
hints: vec![],
span: Some(func_def.span.clone()),
});
return CodeMaker::default();
}
}

let rel_path = make_relative_path(entrypoint_dir.as_str(), extern_path.as_str());
let rel_path = Utf8PathBuf::from(rel_path);

let mut path_components = rel_path.components();

Expand Down Expand Up @@ -1692,10 +1705,11 @@ impl<'a> JSifier<'a> {
Ok(()) => {}
Err(err) => report_diagnostic(err.into()),
}

match self.output_files.borrow_mut().add_file(
sourcemap_file,
code.generate_sourcemap(
root_source.as_str(),
&make_relative_path(self.out_dir.as_str(), &root_source),
self.source_files.get_file(root_source.as_str()).unwrap(),
filename.as_str(),
),
Expand Down
40 changes: 17 additions & 23 deletions libs/wingsdk/src/shared/bundling.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as crypto from "crypto";
import { mkdirSync, writeFileSync } from "fs";
import { join, relative, resolve } from "path";
import { join, resolve } from "path";
import { normalPath } from "./misc";

const SDK_PATH = normalPath(resolve(__dirname, "..", ".."));
Expand All @@ -25,7 +25,6 @@ export function createBundle(
external: string[] = [],
outputDir?: string
): Bundle {
const originalEntrypointDir = normalPath(resolve(entrypoint, ".."));
const outdir = resolve(outputDir ?? entrypoint + ".bundle");
mkdirSync(outdir, { recursive: true });

Expand All @@ -41,9 +40,7 @@ export function createBundle(
let esbuild = esbuilder.buildSync({
bundle: true,
entryPoints: [normalPath(resolve(entrypoint))],
outdir: originalEntrypointDir,
sourceRoot: originalEntrypointDir + "/",
absWorkingDir: originalEntrypointDir,
outfile,
// otherwise there are problems with running azure cloud functions:
// https://stackoverflow.com/questions/70332883/webpack-azure-storage-blob-node-fetch-abortsignal-issue
keepNames: true,
Expand All @@ -55,7 +52,7 @@ export function createBundle(
"@winglang/sdk": SDK_PATH,
},
minify: false,
sourcemap: "external",
sourcemap: "linked",
platform: "node",
target: "node18",
external,
Expand All @@ -67,33 +64,30 @@ export function createBundle(
throw new Error(`Failed to bundle function: ${errors}`);
}

const output = esbuild.outputFiles[1];
let fileContents = new TextDecoder().decode(output.contents);
const bundleOutput = esbuild.outputFiles[1];

// sourcemap hacks for winglang:
// source paths in sourcemap are incorrect and need to be fixed
// ensure source paths have posix path separators
const sourcemapData = JSON.parse(
new TextDecoder().decode(esbuild.outputFiles[0].contents)
);

// ensure sourceRoot has posix path separators
sourcemapData.sourceRoot = normalPath(sourcemapData.sourceRoot);

for (const [idx, source] of Object.entries(sourcemapData.sources)) {
if ((source as any).endsWith(".w")) {
const absolutePath = `/${source}`;
const relativePath = relative(originalEntrypointDir, absolutePath);
sourcemapData.sources[idx] = relativePath;
}
if (sourcemapData.sourceRoot) {
sourcemapData.sourceRoot = normalPath(sourcemapData.sourceRoot);
}

fileContents += `//# sourceMappingURL=${soucemapFilename}`;
for (const [idx, source] of Object.entries(
sourcemapData.sources as string[]
)) {
sourcemapData.sources[idx] = normalPath(source);
}

writeFileSync(outfile, fileContents);
writeFileSync(outfile, bundleOutput.contents);
writeFileSync(outfileMap, JSON.stringify(sourcemapData));

// calculate a md5 hash of the contents of asset.path
const codeHash = crypto.createHash("md5").update(fileContents).digest("hex");
const codeHash = crypto
.createHash("md5")
.update(bundleOutput.contents)
.digest("hex");

return {
entrypointPath: outfile,
Expand Down
7 changes: 6 additions & 1 deletion libs/wingsdk/src/simulator/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,13 @@ export function makeSimulatorClient(url: string, handle: string) {

let err = new Error();
err.message = parsed.error?.message;
err.stack = parsed.error?.stack;
err.name = parsed.error?.name;

if (parsed.error?.stack) {
// combine the stack trace from the server with the stack trace from the client
err.stack = `${parsed.error.stack}\n${err.stack}`;
}

throw err;
}

Expand Down
30 changes: 27 additions & 3 deletions libs/wingsdk/src/util/enhanced-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { stat } from "node:fs/promises";
import { relative, resolve, sep, join } from "node:path";
import type Chalk from "chalk";
import type StackTracey from "stacktracey";
import { normalPath } from "../shared/misc";

export interface PrettyPrintErrorOptions {
/**
Expand Down Expand Up @@ -65,15 +66,27 @@ export async function prettyPrintError(

const message = fBold(fRed("runtime error: ")) + fRed(originalMessage);

st = await st.clean().withSourcesAsync();
st = await st
.clean()
.filter((item) => !item.native)
// strip node internals
.filter((item) => !item.file.startsWith("node:"))
// strip wingsdk
.filter((item) => !normalPath(item.file).includes("/libs/wingsdk/src/"))
// special: remove the handler wrapper (See `cloud.Function` entrypoint for where this comes from)
.filter((item) => !normalPath(item.file).match(/\.wing\/handler_\w+\.js$/))
.withSourcesAsync();
MarkMcCulloh marked this conversation as resolved.
Show resolved Hide resolved

let traceWithSources = st.items.filter((item) => !item.native);
let traceWithSources = st.items;

// special handling: If the bottom of the stack is a js file

if (traceWithSources.length === 0) {
return message;
}

let interestingRoot = options?.sourceEntrypoint;

if (
interestingRoot !== undefined &&
(await stat(interestingRoot)
Expand Down Expand Up @@ -178,10 +191,21 @@ function printItem(item: StackTracey.Entry) {
calleeShort = "";
}

if (item.callee.match(/\$Closure\d+\.handle$/)) {
// inflight closures use "handle" as a way to represent calling the inflight itself
calleeShort = "";
}

if (item.fileName.endsWith(".w") && calleeShort.startsWith("async ")) {
// In userland wing traces, async = inflight and is currently redundant to mention
calleeShort = calleeShort.replace("async ", "");
}

const file = item.file;
const line = item.line;
const column = item.column;
return `at ${calleeShort}(${file}:${line}:${column})`;

return `at ${calleeShort}${file}:${line}:${column}`;
}

export function rewriteCommonError(error: Error): Error {
Expand Down
24 changes: 12 additions & 12 deletions tools/hangar/__snapshots__/error.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ exports[`bool_from_json.test.w 1`] = `
|
5 | let a: bool = bool.fromJson(j.get(\\"a\\"));
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/bool_from_json.test.w:5:15


Tests 1 failed (1)
Expand All @@ -24,7 +24,7 @@ exports[`num_from_str.test.w 1`] = `
| // If it is run with other tests, subsequent failures will be ignored in snapshot.
3 | let a: num = num.fromStr(\\"123a\\");
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/num_from_str.test.w:3:14


Tests 1 failed (1)
Expand All @@ -41,7 +41,7 @@ exports[`number_from_json.test.w 1`] = `
|
5 | let a: num = num.fromJson(j.get(\\"a\\"));
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/number_from_json.test.w:5:14


Tests 1 failed (1)
Expand All @@ -63,7 +63,7 @@ For more information, see https://www.winglang.io/docs/concepts/application-tree
| let bucket1 = new cloud.Bucket();
4 | let bucket2 = new cloud.Bucket();
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/repeat_construct_id.test.w:4:15


Tests 1 failed (1)
Expand All @@ -85,7 +85,7 @@ For more information, see https://www.winglang.io/docs/concepts/application-tree
| let bucket1 = new cloud.Bucket() as \\"{make_name()}\\";
8 | let bucket2 = new cloud.Bucket() as \\"{make_name()}\\";
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/repeat_construct_id2.test.w:8:15


Tests 1 failed (1)
Expand All @@ -102,7 +102,7 @@ exports[`string_from_json.test.w 1`] = `
|
5 | let a: str = str.fromJson(j.get(\\"a\\"));
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/string_from_json.test.w:5:14


Tests 1 failed (1)
Expand All @@ -119,7 +119,7 @@ exports[`struct_from_json_1.test.w 1`] = `
|
11 | Person.fromJson(j);
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/struct_from_json_1.test.w:11:1


Tests 1 failed (1)
Expand All @@ -137,7 +137,7 @@ exports[`struct_from_json_2.test.w 1`] = `
|
22 | Student.fromJson(missingAdvisor);
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/struct_from_json_2.test.w:22:1


Tests 1 failed (1)
Expand All @@ -155,7 +155,7 @@ exports[`struct_from_json_3.test.w 1`] = `
|
26 | Student.fromJson(invalidAdvisorInArray);
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/struct_from_json_3.test.w:26:1


Tests 1 failed (1)
Expand All @@ -172,7 +172,7 @@ exports[`struct_from_json_4.test.w 1`] = `
|
27 | Student.fromJson(invalidAdvisorInArray);
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/struct_from_json_4.test.w:27:1


Tests 1 failed (1)
Expand All @@ -189,7 +189,7 @@ exports[`struct_from_json_5.test.w 1`] = `
|
16 | Foo.fromJson(jFoo);
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/struct_from_json_5.test.w:16:1


Tests 1 failed (1)
Expand All @@ -202,7 +202,7 @@ exports[`utilities.test.w 1`] = `
--> ../../../examples/tests/error/utilities.test.w:1:1
1 | assert(false);
| ^
at (<ABSOLUTE>:LINE:COL)
at <ABSOLUTE>/utilities.test.w:1:1


Tests 1 failed (1)
Expand Down
Loading
Loading