Skip to content

Commit 718b5e8

Browse files
authored
Merge branch 'develop' into remove-debug-console-log-preview
2 parents 0472f35 + 7f17b8a commit 718b5e8

16 files changed

Lines changed: 213 additions & 99 deletions

File tree

client/modules/About/pages/About.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ export const About = () => {
167167
<a
168168
href="https://github.com/processing/p5.js-web-editor/releases"
169169
target="_blank"
170-
rel="noreferrer"
170+
rel="noopener noreferrer"
171171
>
172172
{t('About.WebEditor')}: <span>v{packageData?.version}</span>
173173
</a>
@@ -176,7 +176,7 @@ export const About = () => {
176176
<a
177177
href="https://github.com/processing/p5.js/releases"
178178
target="_blank"
179-
rel="noreferrer"
179+
rel="noopener noreferrer"
180180
>
181181
p5.js: <span>v{p5version}</span>
182182
</a>

client/modules/IDE/actions/assets.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ export function getAssets() {
3030
export function deleteAssetRequest(assetKey) {
3131
return async (dispatch) => {
3232
try {
33-
await apiClient.delete(`/S3/${assetKey}`);
33+
const path = assetKey.split('/').pop();
34+
await apiClient.delete(
35+
`/S3/delete?objectKey=${encodeURIComponent(path)}`
36+
);
3437
dispatch(deleteAsset(assetKey));
3538
} catch (error) {
3639
dispatch({

client/modules/IDE/components/AssetListRow.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const AssetMenu = ({ item: asset }) => {
2222
return (
2323
<TableDropdown aria-label={t('AssetList.ToggleOpenCloseARIA')}>
2424
<MenuItem onClick={handleAssetDelete}>{t('AssetList.Delete')}</MenuItem>
25-
<MenuItem href={asset.url} target="_blank">
25+
<MenuItem href={asset.url} target="_blank" rel="noopener noreferrer">
2626
{t('AssetList.OpenNewTab')}
2727
</MenuItem>
2828
</TableDropdown>

client/modules/IDE/components/Preferences/index.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ export default function Preferences() {
118118
const markdownComponents = useMemo(() => {
119119
// eslint-disable-next-line react/no-unstable-nested-components
120120
const ExternalLink = ({ children, ...props }) => (
121-
<a {...props} target="_blank">
121+
<a {...props} target="_blank" rel="noopener noreferrer">
122122
{children}
123123
</a>
124124
);
@@ -618,7 +618,7 @@ export default function Preferences() {
618618
<legend className="preference__warning">
619619
<a
620620
target="_blank"
621-
rel="noreferrer"
621+
rel="noopener noreferrer"
622622
href={`https://${
623623
versionInfo.isVersion2 ? 'beta.' : ''
624624
}p5js.org/reference/p5.sound`}

client/modules/IDE/components/QuickAddList/QuickAddList.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ const Item = ({ isAdded, onSelect, name, url }) => {
3737
className="quick-add__item-view"
3838
to={url}
3939
target="_blank"
40+
rel="noopener noreferrer"
4041
onClick={(e) => e.stopPropagation()}
4142
>
4243
{t('QuickAddList.View')}

client/modules/IDE/components/show-hint.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,15 @@ import CodeMirror from 'codemirror';
323323
return `<div class="hint-container">${hintHTML}</div>`;
324324
}
325325
}
326-
326+
327+
327328
function getInlineHintSuggestion(cm, focus, token) {
328329
let tokenLength = token.string.length;
329330
if (token.string === '.') {
330331
tokenLength -= 1;
331332
}
332333
const name = focus.item?.text;
334+
333335
const suggestionItem = focus.item;
334336
// builds the remainder of the suggestion excluding what user already typed
335337
const baseCompletion = `<span class="inline-hinter-suggestion">${suggestionItem.text.slice(

client/utils/parseURLParams.test.js

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { parseUrlParams } from './parseURLParams';
2+
import { p5Versions, currentP5Version } from '../../common/p5Versions';
3+
4+
function getVersionString(
5+
item: string | { version: string; label: string }
6+
): string {
7+
return typeof item === 'string' ? item : item.version;
8+
}
9+
10+
const p5VersionStrings = p5Versions.map(getVersionString);
11+
12+
describe('parseUrlParams', () => {
13+
describe('default behavior', () => {
14+
test('returns defaults when no params are provided', () => {
15+
const url = 'https://example.com';
16+
const result = parseUrlParams(url);
17+
18+
expect(result).toEqual({
19+
version: currentP5Version,
20+
sound: true,
21+
preload: false,
22+
shapes: false,
23+
data: false
24+
});
25+
});
26+
27+
test('falls back to defaults for unsupported inputs', () => {
28+
const url =
29+
'https://example.com?version=A&sound=A&preload=A&shapes=A&data=A';
30+
const result = parseUrlParams(url);
31+
32+
expect(result).toEqual({
33+
version: currentP5Version,
34+
sound: true,
35+
preload: false,
36+
shapes: false,
37+
data: false
38+
});
39+
});
40+
});
41+
42+
describe('version parsing', () => {
43+
// Uses regex since p5Versions may be updated over time.
44+
// Checks to ensure version is valid too.
45+
46+
test('parses a valid p5 version and falls back for invalid versions', () => {
47+
const good = parseUrlParams('https://example.com?version=1.4.0');
48+
expect(good.version).toBe('1.4.0');
49+
50+
const bad = parseUrlParams('https://example.com?version=invalid-version');
51+
expect(bad.version).toBe(currentP5Version);
52+
});
53+
54+
test('parses major.minor version 0.5.x to newest patch', () => {
55+
const url = 'https://example.com?version=0.5';
56+
const result = parseUrlParams(url);
57+
58+
expect(result.version).toMatch(/^0\.5\.\d+$/);
59+
expect(p5VersionStrings).toContain(result.version);
60+
});
61+
62+
test('parses major version 0 to newest 0.x version', () => {
63+
const url = 'https://example.com?version=0';
64+
const result = parseUrlParams(url);
65+
66+
expect(result.version).toMatch(/^0\.\d+\.\d+$/);
67+
expect(p5VersionStrings).toContain(result.version);
68+
});
69+
70+
test('parses major version 1 to newest 1.x version', () => {
71+
const url = 'https://example.com?version=1';
72+
const result = parseUrlParams(url);
73+
expect(result.version).toMatch(/^1\.\d+\.\d+$/);
74+
expect(p5VersionStrings).toContain(result.version);
75+
});
76+
77+
test('parses major.minor version 1.1.x to newest patch', () => {
78+
const url = 'https://example.com?version=1.1';
79+
const result = parseUrlParams(url);
80+
expect(result.version).toMatch(/^1\.1\.\d+$/);
81+
expect(p5VersionStrings).toContain(result.version);
82+
});
83+
84+
test('parses major version 2 to newest 2.x version', () => {
85+
const url = 'https://example.com?version=2';
86+
const result = parseUrlParams(url);
87+
expect(result.version).toMatch(/^2\.\d+\.\d+$/);
88+
expect(p5VersionStrings).toContain(result.version);
89+
});
90+
91+
test('parses major.minor version 2.0.x to newest patch', () => {
92+
const url = 'https://example.com?version=2.0';
93+
const result = parseUrlParams(url);
94+
expect(result.version).toMatch(/^2\.0\.\d+$/);
95+
expect(p5VersionStrings).toContain(result.version);
96+
});
97+
});
98+
99+
describe('boolean param parsing', () => {
100+
test('parses boolean-like params for sound/preload/shapes/data (true variants)', () => {
101+
const trueVariants = ['on', 'true', '1', 'ON', 'True'];
102+
103+
trueVariants.forEach((v) => {
104+
const url = `https://example.com?sound=${v}&preload=${v}&shapes=${v}&data=${v}`;
105+
const result = parseUrlParams(url);
106+
expect(result.sound).toBe(true);
107+
expect(result.preload).toBe(true);
108+
expect(result.shapes).toBe(true);
109+
expect(result.data).toBe(true);
110+
});
111+
});
112+
113+
test('parses boolean-like params for sound/preload/shapes/data (false variants)', () => {
114+
const falseVariants = ['off', 'false', '0', 'OFF', 'False'];
115+
116+
falseVariants.forEach((v) => {
117+
const url = `https://example.com?sound=${v}&preload=${v}&shapes=${v}&data=${v}`;
118+
const result = parseUrlParams(url);
119+
expect(result.sound).toBe(false);
120+
expect(result.preload).toBe(false);
121+
expect(result.shapes).toBe(false);
122+
expect(result.data).toBe(false);
123+
});
124+
});
125+
});
126+
});
Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
import { p5Versions, currentP5Version } from '../../common/p5Versions';
22

3+
export interface ParsedUrlParams {
4+
version: string;
5+
sound: boolean;
6+
preload: boolean;
7+
shapes: boolean;
8+
data: boolean;
9+
}
10+
311
const DEFAULTS = {
412
sound: true,
513
preload: false,
614
shapes: false,
715
data: false
816
};
917

10-
/**
11-
* Sorts version strings in descending order and returns the highest version
12-
* @param {string[]} versions - Array of version strings (e.g., ['1.11.2', '1.11.1'])
13-
* @returns {string} The highest version from the array
14-
*/
15-
function getNewestVersion(versions) {
18+
function getVersionString(
19+
item: string | { version: string; label: string }
20+
): string {
21+
return typeof item === 'string' ? item : item.version;
22+
}
23+
24+
const p5VersionStrings = p5Versions.map(getVersionString);
25+
26+
function getNewestVersion(versions: string[]): string {
1627
return versions.sort((a, b) => {
1728
const pa = a.split('.').map((n) => parseInt(n, 10));
1829
const pb = b.split('.').map((n) => parseInt(n, 10));
@@ -25,18 +36,18 @@ function getNewestVersion(versions) {
2536
})[0];
2637
}
2738

28-
function validateVersion(version) {
39+
function validateVersion(version: string | null): string {
2940
if (!version) return currentP5Version;
3041

3142
const ver = String(version).trim();
3243

33-
if (p5Versions.includes(ver)) return ver;
44+
if (p5VersionStrings.includes(ver)) return ver;
3445

3546
// if only major.minor provided like "1.11"
3647
const majorMinorMatch = /^(\d+)\.(\d+)$/.exec(ver);
3748
if (majorMinorMatch) {
3849
const [, major, minor] = majorMinorMatch;
39-
const matches = p5Versions.filter((v) => {
50+
const matches = p5VersionStrings.filter((v) => {
4051
const parts = v.split('.');
4152
return parts[0] === major && parts[1] === minor;
4253
});
@@ -49,7 +60,7 @@ function validateVersion(version) {
4960
const majorOnlyMatch = /^(\d+)$/.exec(ver);
5061
if (majorOnlyMatch) {
5162
const [, major] = majorOnlyMatch;
52-
const matches = p5Versions.filter((v) => v.split('.')[0] === major);
63+
const matches = p5VersionStrings.filter((v) => v.split('.')[0] === major);
5364
if (matches.length) {
5465
return getNewestVersion(matches);
5566
}
@@ -58,7 +69,7 @@ function validateVersion(version) {
5869
return currentP5Version;
5970
}
6071

61-
function validateBool(value, defaultValue) {
72+
function validateBool(value: string | null, defaultValue: boolean): boolean {
6273
if (!value) return defaultValue;
6374

6475
const v = String(value).trim().toLowerCase();
@@ -72,7 +83,13 @@ function validateBool(value, defaultValue) {
7283
return defaultValue;
7384
}
7485

75-
export function parseUrlParams(url) {
86+
/**
87+
* Parses URL parameters for version and boolean flags.
88+
*
89+
* @param url - The URL string to parse.
90+
* @returns Parsed and validated URL parameters including version and library flags.
91+
*/
92+
export function parseUrlParams(url: string): ParsedUrlParams {
7693
const params = new URLSearchParams(
7794
new URL(url, 'https://dummy.origin').search
7895
);

contributor_docs/preparing_a_pull_request.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,17 @@ Then ask git about the latest changes.
5151
git status
5252

5353
## Pull Request Templates
54-
Once you've opened your pull request, please ensure that you follow the guidelines.
54+
55+
Once you've opened your pull request, please ensure that you follow the guidelines **and verify the following before submitting for review:**
56+
57+
- ✅ Your code has no linting errors (`npm run lint`)
58+
- ✅ All tests pass successfully (`npm run test`)
59+
- ✅ Your branch name is unique and based off the latest `develop` branch
60+
- ✅ The pull request title and description clearly describe the change
61+
- ✅ Your pull request links to the related issue number (e.g., `Fixes #1234`)
62+
- ✅ Screenshots or videos are included if the change affects the user interface
63+
64+
Following these steps helps maintain code quality and makes it easier for maintainers to review and merge your contribution.
5565

5666
## CONFLICTS
5767
You may have some conflicts! It's okay. Feel free to ask for help. If merging with the latest upstream `develop` branch causes conflicts, you can always make a pull request with the upstream repository, which makes the merge conflicts public.

0 commit comments

Comments
 (0)