Skip to content

client: Use prettier for formatting #1493

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 1 commit into from
Jul 11, 2024
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
5 changes: 4 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@
### Other changes
- `tidy` PHP extension is now required if you want to use “Content extractor” spout. ([#1392](https://github.com/fossar/selfoss/pull/1392))
- Password hashing helper page will delegate the hashing to server again. ([#1401](https://github.com/fossar/selfoss/pull/1401))
- Back-end source code is now checked using [PHPStan](https://phpstan.org/). ([#1409](https://github.com/fossar/selfoss/pull/1409))
- Content Extraction spout will no longer try to extract content we have already extracted. ([#1413](https://github.com/fossar/selfoss/pull/1413))
- Source filters are stricter, they need to start and end with a `/`. ([#1423](https://github.com/fossar/selfoss/pull/1423))
- OPML importer has been merged into the React client. ([#1442](https://github.com/fossar/selfoss/pull/1442))
- Web requests will send `Accept-Encoding` header. ([#1482](https://github.com/fossar/selfoss/pull/1482))

#### For developers
- Back-end source code is now checked using [PHPStan](https://phpstan.org/). ([#1409](https://github.com/fossar/selfoss/pull/1409))
- [Prettier](https://prettier.io/) is now used for code formatting. ([#1493](https://github.com/fossar/selfoss/pull/1493))

## 2.19 – 2022-10-12
**This version requires PHP ~~5.6~~ 7.2 (see known regressions section) or newer. It is also the last version to support PHP 7.**

Expand Down
29 changes: 2 additions & 27 deletions client/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,21 @@
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended"
"plugin:react-hooks/recommended",
"prettier"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"no-eval": "error",
"array-bracket-spacing": "error",
"no-array-constructor": "error",
"block-spacing": "error",
"brace-style": "error",
"camelcase": "error",
"comma-dangle": ["error", "only-multiline"],
"comma-spacing": "error",
"comma-style": "error",
"curly": "error",
"eol-last": "error",
"func-call-spacing": "error",
"indent": ["error", 4],
"key-spacing": "error",
"keyword-spacing": "error",
"linebreak-style": ["error", "unix"],
"max-statements-per-line": ["error", {"max": 1}],
"no-multiple-empty-lines": "error",
"no-trailing-spaces": "error",
"no-use-before-define": "error",
"no-whitespace-before-property": "error",
"object-curly-newline": ["error", {"multiline": true, "consistent": true}],
"one-var-declaration-per-line": "error",
"quotes": ["error", "single", {"avoidEscape": true}],
"react-hooks/exhaustive-deps": ["warn", {
"additionalHooks": "(useStateWithDeps)"
}],
"semi": "error",
"semi-spacing": "error",
"space-before-blocks": "error",
"space-before-function-paren": ["error", "never"],
"space-in-parens": "error",
"space-infix-ops": "error",
"unicode-bom": "error"
},
"env": {
Expand Down
2 changes: 1 addition & 1 deletion client/images/wallabag.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion client/js/Filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
export const FilterType = {
NEWEST: 'newest',
UNREAD: 'unread',
STARRED: 'starred'
STARRED: 'starred',
};
186 changes: 100 additions & 86 deletions client/js/helpers/ajax.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,22 @@ export const rejectUnless = (pred) => (response) => {
}
};


/**
* fetch API considers a HTTP error a successful state.
* Passing this function as a Promise handler will make the promise fail when HTTP error occurs.
*/
export const rejectIfNotOkay = (response) => {
return rejectUnless(response => response.ok)(response);
return rejectUnless((response) => response.ok)(response);
};

/**
* Override fetch options.
*/
export const options = (newOpts) => (fetch) => (url, opts = {}) => fetch(url, mergeDeepLeft(opts, newOpts));
export const options =
(newOpts) =>
(fetch) =>
(url, opts = {}) =>
fetch(url, mergeDeepLeft(opts, newOpts));

/**
* Override just a single fetch option.
Expand All @@ -45,7 +48,6 @@ export const headers = (value) => option('headers', value);
*/
export const header = (name, value) => headers({ [name]: value });


/**
* Lift a wrapper function so that it can wrap a function returning more than just a Promise.
*
Expand All @@ -56,102 +58,115 @@ export const header = (name, value) => headers({ [name]: value });
*
* @sig ((...params → Promise) → (...params → Promise)) → (...params → {promise: Promise, ...}) → (...params → {promise: Promise, ...})
*/
export const liftToPromiseField = (wrapper) => (f) => (...params) => {
let rest;
const promise = wrapper((...innerParams) => {
const {promise, ...innerRest} = f(...innerParams);
rest = innerRest;
return promise;
})(...params);

return {promise, ...rest};
};

export const liftToPromiseField =
(wrapper) =>
(f) =>
(...params) => {
let rest;
const promise = wrapper((...innerParams) => {
const { promise, ...innerRest } = f(...innerParams);
rest = innerRest;
return promise;
})(...params);

return { promise, ...rest };
};

/**
* Wrapper for fetch that makes it cancellable using AbortController.
* @return {controller: AbortController, promise: Promise}
*/
export const makeAbortableFetch = (fetch) => (url, opts = {}) => {
const controller = opts.abortController || new AbortController();
const promise = fetch(url, {
signal: controller.signal,
...opts
});

return {controller, promise};
};
export const makeAbortableFetch =
(fetch) =>
(url, opts = {}) => {
const controller = opts.abortController || new AbortController();
const promise = fetch(url, {
signal: controller.signal,
...opts,
});

return { controller, promise };
};

/**
* Wrapper for abortable fetch that adds timeout support.
* @return {controller: AbortController, promise: Promise}
*/
export const makeFetchWithTimeout = (abortableFetch) => (url, opts = {}) => {
// offline db consistency requires ajax calls to fail reliably,
// so we enforce a default timeout on ajax calls
const { timeout = 60000, ...rest } = opts;
const {controller, promise} = abortableFetch(url, rest);

if (timeout !== 0) {
const newPromise = promise.catch((error) => {
// Change error name in case of time out so that we can
// distinguish it from explicit abort.
if (error.name === 'AbortError' && promise.timedOut) {
error = new TimeoutError(`Request timed out after ${timeout / 1000} seconds`);
}

throw error;
});

setTimeout(() => {
promise.timedOut = true;
controller.abort();
}, timeout);

return {controller, promise: newPromise};
}

return {controller, promise};
};

export const makeFetchWithTimeout =
(abortableFetch) =>
(url, opts = {}) => {
// offline db consistency requires ajax calls to fail reliably,
// so we enforce a default timeout on ajax calls
const { timeout = 60000, ...rest } = opts;
const { controller, promise } = abortableFetch(url, rest);

if (timeout !== 0) {
const newPromise = promise.catch((error) => {
// Change error name in case of time out so that we can
// distinguish it from explicit abort.
if (error.name === 'AbortError' && promise.timedOut) {
error = new TimeoutError(
`Request timed out after ${timeout / 1000} seconds`,
);
}

throw error;
});

setTimeout(() => {
promise.timedOut = true;
controller.abort();
}, timeout);

return { controller, promise: newPromise };
}

return { controller, promise };
};

/**
* Wrapper for fetch that makes it fail on HTTP errors.
* @return Promise
*/
export const makeFetchFailOnHttpErrors = (fetch) => (url, opts = {}) => {
const { failOnHttpErrors = true, ...rest } = opts;
const promise = fetch(url, rest);

if (failOnHttpErrors) {
return promise.then(rejectIfNotOkay);
}
export const makeFetchFailOnHttpErrors =
(fetch) =>
(url, opts = {}) => {
const { failOnHttpErrors = true, ...rest } = opts;
const promise = fetch(url, rest);

return promise;
};
if (failOnHttpErrors) {
return promise.then(rejectIfNotOkay);
}

return promise;
};

/**
* Wrapper for fetch that converts URLSearchParams body of GET requests to query string.
*/
export const makeFetchSupportGetBody = (fetch) => (url, opts = {}) => {
const { body, method, ...rest } = opts;

let newUrl = url;
let newOpts = opts;
if (Object.keys(opts).includes('method') && Object.keys(opts).includes('body') && method.toUpperCase() === 'GET' && body instanceof URLSearchParams) {
const [main, ...fragments] = newUrl.split('#');
const separator = main.includes('?') ? '&' : '?';
// append the body to the query string
newUrl = `${main}${separator}${body.toString()}#${fragments.join('#')}`;
// remove the body since it has been moved to URL
newOpts = { method, rest };
}

return fetch(newUrl, newOpts);
};

export const makeFetchSupportGetBody =
(fetch) =>
(url, opts = {}) => {
const { body, method, ...rest } = opts;

let newUrl = url;
let newOpts = opts;
if (
Object.keys(opts).includes('method') &&
Object.keys(opts).includes('body') &&
method.toUpperCase() === 'GET' &&
body instanceof URLSearchParams
) {
const [main, ...fragments] = newUrl.split('#');
const separator = main.includes('?') ? '&' : '?';
// append the body to the query string
newUrl = `${main}${separator}${body.toString()}#${fragments.join('#')}`;
// remove the body since it has been moved to URL
newOpts = { method, rest };
}

return fetch(newUrl, newOpts);
};

/**
* Cancellable fetch with timeout support that rejects on HTTP errors.
Expand All @@ -166,23 +181,22 @@ export const fetch = pipe(
makeFetchFailOnHttpErrors,
makeFetchSupportGetBody,
makeAbortableFetch,
makeFetchWithTimeout
makeFetchWithTimeout,
)(window.fetch);


export const get = liftToPromiseField(option('method', 'GET'))(fetch);


export const post = liftToPromiseField(option('method', 'POST'))(fetch);


export const delete_ = liftToPromiseField(option('method', 'DELETE'))(fetch);


/**
* Using URLSearchParams directly handles dictionaries inconveniently.
* For example, it joins arrays with commas or includes undefined keys.
*/
export const makeSearchParams = (data) => new URLSearchParams(formurlencoded(data, {
ignorenull: true
}));
export const makeSearchParams = (data) =>
new URLSearchParams(
formurlencoded(data, {
ignorenull: true,
}),
);
16 changes: 3 additions & 13 deletions client/js/helpers/authorizations.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
import { useListenableValue } from './hooks';
import { useMemo } from 'react';


export function useLoggedIn() {
return useListenableValue(selfoss.loggedin);
}

export function useAllowedToRead() {
const loggedIn = useLoggedIn();

return useMemo(
() => selfoss.isAllowedToRead(),
[loggedIn],
);
return useMemo(() => selfoss.isAllowedToRead(), [loggedIn]);
}

export function useAllowedToUpdate() {
const loggedIn = useLoggedIn();

return useMemo(
() => selfoss.isAllowedToUpdate(),
[loggedIn],
);
return useMemo(() => selfoss.isAllowedToUpdate(), [loggedIn]);
}

export function useAllowedToWrite() {
const loggedIn = useLoggedIn();

return useMemo(
() => selfoss.isAllowedToWrite(),
[loggedIn],
);
return useMemo(() => selfoss.isAllowedToWrite(), [loggedIn]);
}
8 changes: 6 additions & 2 deletions client/js/helpers/color.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@
*
* @see https://24ways.org/2010/calculating-color-contrast/
*/
export function colorByBrightness(hexColor, darkColor = '#555', brightColor = '#EEE') {
export function colorByBrightness(
hexColor,
darkColor = '#555',
brightColor = '#EEE',
) {
// Strip hash sign.
const color = hexColor.substr(1);
const r = parseInt(color.substr(0, 2), 16);
const g = parseInt(color.substr(2, 2), 16);
const b = parseInt(color.substr(4, 2), 16);
const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000;
const yiq = (r * 299 + g * 587 + b * 114) / 1000;
return yiq >= 128 ? darkColor : brightColor;
}
Loading