Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 8 additions & 3 deletions packages/builder/lib/lbt/bundle/Builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {SectionType} from "./BundleDefinition.js";
import BundleWriter from "./BundleWriter.js";
import {getLogger} from "@ui5/logger";
import semver from "semver";
import parseJSON from "../../utils/json.js";
const log = getLogger("lbt:bundle:Builder");

const sourceMappingUrlPattern = /\/\/# sourceMappingURL=(\S+)\s*$/;
Expand Down Expand Up @@ -502,9 +503,9 @@ class BundleBuilder {
let fileContent = stripBOM((await resource.buffer()).toString());
if ( this.optimize ) {
try {
fileContent = JSON.stringify( JSON.parse( fileContent) );
fileContent = JSON.stringify( parseJSON( fileContent, moduleName) );
} catch (e) {
log.verbose(`Failed to parse JSON file ${moduleName}. Ignoring error, skipping compression.`);
log.verbose(`Skipping compression of module ${moduleName}.`);
log.verbose(e);
}
}
Expand Down Expand Up @@ -673,6 +674,7 @@ class BundleBuilder {

async getSourceMapForModule({moduleName, moduleContent, resourcePath}) {
let moduleSourceMap = null;
let sourceMapOriginPath = null;
let newModuleContent = moduleContent;

const sourceMapUrlMatch = moduleContent.match(sourceMappingUrlPattern);
Expand All @@ -691,6 +693,7 @@ class BundleBuilder {
if (sourceMapUrl.startsWith(expectedTypeAndEncoding)) {
const base64Content = sourceMapUrl.slice(expectedTypeAndEncoding.length);
moduleSourceMap = Buffer.from(base64Content, "base64").toString();
sourceMapOriginPath = `${moduleName} (inline source map)`;
} else {
log.warn(
`Source map reference in module ${moduleName} is a data URI but has an unexpected` +
Expand All @@ -709,6 +712,7 @@ class BundleBuilder {
try {
const sourceMapResource = await this.pool.findResource(sourceMapPath);
moduleSourceMap = (await sourceMapResource.buffer()).toString();
sourceMapOriginPath = sourceMapPath;
} catch (e) {
// No input source map
log.warn(`Unable to read source map for module ${moduleName}: ${e.message}`);
Expand All @@ -722,6 +726,7 @@ class BundleBuilder {
try {
const sourceMapResource = await this.pool.findResource(sourceMapFileCandidate);
moduleSourceMap = (await sourceMapResource.buffer()).toString();
sourceMapOriginPath = sourceMapFileCandidate;
} catch (e) {
// No input source map
log.silly(`Could not find a source map for module ${moduleName}: ${e.message}`);
Expand All @@ -730,7 +735,7 @@ class BundleBuilder {


if (moduleSourceMap) {
moduleSourceMap = JSON.parse(moduleSourceMap);
moduleSourceMap = parseJSON(moduleSourceMap, sourceMapOriginPath);

// Check for index map, which is currently not supported
if (Array.isArray(moduleSourceMap.sections)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {getLogger} from "@ui5/logger";
const log = getLogger("builder:processors:bundlers:flexChangesBundler");
import {createResource} from "@ui5/fs/resourceFactory";
import parseJSON from "../../utils/json.js";

/**
* @public
Expand Down Expand Up @@ -170,7 +171,7 @@ export default function({resources, options: {pathPrefix, hasFlexBundleVersion},

return Promise.all(resources.map((resource) => {
return resource.getBuffer().then((buffer) => {
return JSON.parse(buffer.toString());
return parseJSON(buffer.toString(), resource.getPath());
});
})).then((changesContent) => {
const nNumberOfChanges = changesContent.length;
Expand Down
3 changes: 2 additions & 1 deletion packages/builder/lib/processors/minifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import os from "node:os";
import workerpool from "workerpool";
import Resource from "@ui5/fs/Resource";
import {getLogger} from "@ui5/logger";
import parseJSON from "../utils/json.js";
const log = getLogger("builder:processors:minifier");
import {setTimeout as setTimeoutPromise} from "node:timers/promises";

Expand Down Expand Up @@ -230,7 +231,7 @@ export default async function({
});

if (sourceMapContent) {
const sourceMapJson = JSON.parse(sourceMapContent);
const sourceMapJson = parseJSON(sourceMapContent, resourcePath + ".map");

if (sourceMapJson.sections) {
// TODO 5.0
Expand Down
4 changes: 3 additions & 1 deletion packages/builder/lib/tasks/utils/dotTheming.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import parseJSON from "../../utils/json.js";

export async function updateLibraryDotTheming({resource, namespace, version, hasThemes}) {
const dotTheming = JSON.parse(await resource.getString());
const dotTheming = parseJSON(await resource.getString(), resource.getPath());

if (!dotTheming.sEntity) {
throw new Error(`Missing 'sEntity' property in ${resource.getPath()}`);
Expand Down
72 changes: 71 additions & 1 deletion packages/builder/test/lib/lbt/bundle/Builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ test.serial("writePreloadModule: with invalid json content", async (t) => {
const result = await builder.writePreloadModule("invalid.json", undefined, invalidJsonResource);

t.is(verboseLogStub.callCount, 2, "called 2 times");
t.is(verboseLogStub.firstCall.args[0], "Failed to parse JSON file invalid.json. Ignoring error, skipping compression.",
t.is(verboseLogStub.firstCall.args[0], "Skipping compression of module invalid.json.",
"first verbose log argument 0 is correct");
t.true(verboseLogStub.secondCall.args[0] instanceof SyntaxError, "second verbose log with SyntaxError");
t.is(verboseLogStub.secondCall.args[0].code, "ERR_INVALID_JSON", "second verbose log error has ERR_INVALID_JSON code");
t.regex(verboseLogStub.secondCall.args[0].message, /JSON/, "second verbose log about incorrect JSON");

t.true(result, "result is true");
Expand Down Expand Up @@ -3288,6 +3289,75 @@ ${SOURCE_MAPPING_URL}=data:application/pony;charset=utf-8;base64,AAAA`
}, "Expected transitive source map has been generated");
});

test("getSourceMapForModule: Data URI with malformed JSON reports inline origin in error", async (t) => {
const pool = new ResourcePool();
const builder = new Builder(pool);
await t.throwsAsync(
builder.getSourceMapForModule({
moduleName: "my/test/module",
resourcePath: "/resources/my/test/module.js",
moduleContent: `// Some content
${SOURCE_MAPPING_URL}=data:application/json;charset=utf-8;base64,${Buffer.from("not json").toString("base64")}`
}),
{
instanceOf: SyntaxError,
message: /my\/test\/module \(inline source map\)/
},
"Error message references the inline source map origin"
);
});

test("getSourceMapForModule: Relative URL with malformed JSON reports resolved path in error", async (t) => {
const pool = new ResourcePool();
pool.addResource({
name: "my/test/module.js.map",
getPath: () => "my/test/module.js.map",
string: function() {
return this.buffer();
},
buffer: async () => "not json"
});
const builder = new Builder(pool);
await t.throwsAsync(
builder.getSourceMapForModule({
moduleName: "my/test/module",
resourcePath: "/resources/my/test/module.js",
moduleContent: `// Some content
${SOURCE_MAPPING_URL}=module.js.map`
}),
{
instanceOf: SyntaxError,
message: /my\/test\/module\.js\.map/
},
"Error message references the resolved source map file path"
);
});

test("getSourceMapForModule: Fallback file with malformed JSON reports candidate path in error", async (t) => {
const pool = new ResourcePool();
pool.addResource({
name: "my/test/module.js.map",
getPath: () => "my/test/module.js.map",
string: function() {
return this.buffer();
},
buffer: async () => "not json"
});
const builder = new Builder(pool);
await t.throwsAsync(
builder.getSourceMapForModule({
moduleName: "my/test/module",
resourcePath: "/resources/my/test/module.js",
moduleContent: "// Some content\n"
}),
{
instanceOf: SyntaxError,
message: /my\/test\/module\.js\.map/
},
"Error message references the fallback source map candidate path"
);
});

test("createTransientSourceMap: includeContent=false", (t) => {
const {createTransientSourceMap} = __localFunctions__;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ test("flexChangesBundler with 2 changes", async (t) => {
flexBundle.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
Expand Down Expand Up @@ -127,6 +128,7 @@ test("includes annotation_changes in flexibility-bundle when hasFlexBundleVersio

const resources = [{
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
}];

Expand Down Expand Up @@ -156,6 +158,7 @@ test("annotation_changes triggers error when hasFlexBundleVersion = false", asyn

const resources = [{
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
}];

Expand Down Expand Up @@ -431,6 +434,7 @@ test("flexChangesBundler has ctrl_variant and hasFlexBundleVersion = true", asyn
entities.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
Expand Down Expand Up @@ -531,12 +535,14 @@ test("flexChangesBundler has ctrl_variant and hasFlexBundleVersion = false", asy
change.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariant.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
Expand Down Expand Up @@ -937,36 +943,42 @@ test("flexChangesBundler with existing flexibility-bundle.json", async (t) => {
changeList.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
compVariants.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
variantDependentControlChange.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariantChange.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariantManagementChange.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariant.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
Expand Down Expand Up @@ -1243,36 +1255,42 @@ test("flexChangesBundler with existing flexibility-bundle.json and missing/wrong
changeList.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
compVariants.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
variantDependentControlChange.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariantChange.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariantManagementChange.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
ctrlVariant.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
Expand Down Expand Up @@ -1396,6 +1414,7 @@ test("flexChangesBundler with existing flexibility-bundle.json and version lower
flexBundle.forEach((change) => {
resources.push({
name: "flexChange",
getPath: () => "/test/change.json",
getBuffer: async () => JSON.stringify(change)
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ test.serial("generateThemeDesignerResources: Library sap.ui.core with existing l
};

const coreLibraryDotThemingResource = {
getPath: () => "/resources/sap/ui/core/.theming",
getString: async () => JSON.stringify({
sEntity: "Library",
sId: "sap/ui/core",
Expand Down Expand Up @@ -348,6 +349,7 @@ test.serial("generateThemeDesignerResources: Library sap.ui.core without themes,
const {sinon, generateThemeDesignerResources, libraryLessGeneratorStub, fsInterfaceStub, ResourceStub} = t.context;

const coreLibraryDotThemingResource = {
getPath: () => "/resources/sap/ui/core/.theming",
getString: async () => JSON.stringify({
sEntity: "Library",
sId: "sap/ui/core",
Expand Down
3 changes: 2 additions & 1 deletion packages/project/lib/graph/Module.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ui5YamlSchema from "./helpers/ui5YamlSchema.js";
import {createReader} from "@ui5/fs/resourceFactory";
import Specification from "../specifications/Specification.js";
import {validate} from "../validation/validator.js";
import parseJSON from "../utils/json.js";

import {getLogger} from "@ui5/logger";

Expand Down Expand Up @@ -395,7 +396,7 @@ class Module {
const reader = this.getReader();
const buildManifestResource = await reader.byPath("/.ui5/build-manifest.json");
if (buildManifestResource) {
return JSON.parse(await buildManifestResource.getString());
return parseJSON(await buildManifestResource.getString(), buildManifestResource.getPath());
}
}

Expand Down
6 changes: 4 additions & 2 deletions packages/project/lib/graph/Workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {promisify} from "node:util";
import {getLogger} from "@ui5/logger";
import Module from "./Module.js";
import {validateWorkspace} from "../validation/validator.js";
import parseJSON from "../utils/json.js";

const readFile = promisify(fs.readFile);
const log = getLogger("graph:Workspace");
Expand Down Expand Up @@ -261,8 +262,9 @@ class Workspace {
* @returns {object} Package json content
*/
async _readPackageJson(modulePath) {
const content = await readFile(path.join(modulePath, "package.json"), "utf8");
return JSON.parse(content);
const packageJsonPath = path.join(modulePath, "package.json");
const content = await readFile(packageJsonPath, "utf8");
return parseJSON(content, packageJsonPath);
}

async _validateConfig() {
Expand Down
Loading
Loading