Skip to content

fix: download site bundle correctly if site name has special chars #262

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

Merged
merged 5 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
"prepare": "sf-install",
"test": "wireit",
"test:nuts": "nyc mocha \"**/*.nut.ts\" --slow 4500 --timeout 600000 --parallel",
"test:spec": "nyc mocha \"test/**/*.spec.ts\" --slow 4500 --timeout 600000 --parallel",
"test:only": "wireit",
"unlink-lwr": "yarn unlink @lwrjs/api @lwrjs/app-service @lwrjs/asset-registry @lwrjs/asset-transformer @lwrjs/auth-middleware @lwrjs/base-view-provider @lwrjs/base-view-transformer @lwrjs/client-modules @lwrjs/config @lwrjs/core @lwrjs/dev-proxy-server @lwrjs/diagnostics @lwrjs/esbuild @lwrjs/everywhere @lwrjs/fs-asset-provider @lwrjs/fs-watch @lwrjs/html-view-provider @lwrjs/instrumentation @lwrjs/label-module-provider @lwrjs/lambda @lwrjs/legacy-npm-module-provider @lwrjs/loader @lwrjs/lwc-module-provider @lwrjs/lwc-ssr @lwrjs/markdown-view-provider @lwrjs/module-bundler @lwrjs/module-registry @lwrjs/npm-module-provider @lwrjs/nunjucks-view-provider @lwrjs/o11y @lwrjs/resource-registry @lwrjs/router @lwrjs/security @lwrjs/server @lwrjs/shared-utils @lwrjs/static @lwrjs/tools @lwrjs/types @lwrjs/view-registry lwr",
"update-snapshots": "node --loader ts-node/esm --no-warnings=ExperimentalWarning \"./bin/dev.js\" snapshot:generate",
Expand Down
31 changes: 31 additions & 0 deletions src/shared/experience/expSite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ export class ExperienceSite {

public async getRemoteMetadata(): Promise<SiteMetadata | undefined> {
if (this.metadataCache.remoteMetadata) return this.metadataCache.remoteMetadata;
// Check if there are special characters in the site name
const isInvalidSiteName = hasSpacesOrSpecialChars(this.siteName);
// const originalSiteName = this.siteName;
if (isInvalidSiteName) {
const updatedSiteName = replaceSpacesAndSpecialChars(this.siteName);
this.siteName = updatedSiteName;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pulkit0555 Is there a reason why we can't do this in the constructor?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nrkruk I was also debating on the same idea in a different PR to add these changes in the constructor but I guess that was missed. Let me add those changes now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2024-11-21 at 2 28 20 PM

const result = await this.org
.getConnection()
.query<{ Name: string; LastModifiedDate: string }>(
Expand Down Expand Up @@ -356,3 +363,27 @@ function getSiteNameFromStaticResource(staticResourceName: string): string {
}
return parts.slice(4).join(' ');
}

export function replaceSpacesAndSpecialChars(value: string): string {
// Replace any special characters with underscore
value = value.replace(/[^a-zA-Z0-9]/g, '_');

// Replace spaces with underscore
value = value.replace(/ /g, '_');

return value;
}

export function hasSpacesOrSpecialChars(value: string): boolean {
// Check for spaces
if (value.includes(' ')) {
return true;
}

// Check for special characters
if (/[^\w]/.test(value)) {
return true;
}

return false;
}
82 changes: 82 additions & 0 deletions test/spec/expSite.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { expect } from 'chai';
import { Connection, Org } from '@salesforce/core';
import sinon from 'sinon';
import {
replaceSpacesAndSpecialChars,
hasSpacesOrSpecialChars,
ExperienceSite,
} from '../../src/shared/experience/expSite.js';

describe('replaceSpacesAndSpecialChars', () => {
it('should replace spaces and special characters with underscores', () => {
const input = 'site#name@with-special%chars with spaces';
const expectedOutput = 'site_name_with_special_chars_with_spaces';
const output = replaceSpacesAndSpecialChars(input);
expect(output).to.equal(expectedOutput);
});
});

describe('hasSpacesOrSpecialChars', () => {
it('should return true if the input string has spaces', () => {
const input = 'Hello World';
const output = hasSpacesOrSpecialChars(input);
expect(output).to.be.true;
});

it('should return true if the input string has special characters', () => {
const input = 'Hello, @#';
const output = hasSpacesOrSpecialChars(input);
expect(output).to.be.true;
});

it('should return false if the input string has neither spaces nor special characters', () => {
const input = 'HelloWorld';
const output = hasSpacesOrSpecialChars(input);
expect(output).to.be.false;
});
});

describe('getRemoteMetadata', () => {
it('should return remote metadata when it exists', async () => {
const org = new Org();
const siteName = 'site@with#special-chars';
const experienceSite = new ExperienceSite(org, siteName);

// Create a mock Connection instance using sinon
const mockConnection = sinon.createStubInstance(Connection);

// Configure the mock to return the desired result when calling query
mockConnection.query.resolves({
done: true,
totalSize: 1,
records: [
{
Name: 'MRT_experience_00DSG00000ECBfZ_0DMSG000001CfA6_site_with_special_chars_10-30_12-47',
LastModifiedDate: '2024-11-12',
},
],
});

// Replace the original connection with the mocked connection
org.getConnection = () => mockConnection;

const remoteMetadata = await experienceSite.getRemoteMetadata();

// Check if the called query matches the expected pattern
const calledQuery = mockConnection.query.args[0][0];
const expectedPattern =
/SELECT Name, LastModifiedDate FROM StaticResource WHERE Name LIKE 'MRT_experience_%_site_with_special_chars/;
expect(calledQuery).to.match(expectedPattern);

expect(remoteMetadata).to.deep.equal({
bundleName: 'MRT_experience_00DSG00000ECBfZ_0DMSG000001CfA6_site_with_special_chars_10-30_12-47',
bundleLastModified: '2024-11-12',
});
});
});