Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • pub/frama-c
  • proidiot/frama-c
  • lthls/frama-c
3 results
Show changes
Commits on Source (148)
Showing
with 244 additions and 164 deletions
......@@ -61,7 +61,6 @@ wp-qualif:
- nix/frama-ci.sh build -A frama-c.wp-qualif
tags:
- nix
allow_failure: true
aorai-prove:
stage: tests
......
......@@ -6,10 +6,11 @@
# Mark "+": change for Frama-C-commits audience (not in html version). #
# Mark "*": bug fixed. #
# Mark "!": change that can break compatibility with existing development. #
# '#nnn' : BTS entry #nnn #
# '#!nnn' : BTS private entry #nnn #
# '##nnn' : Public Gitlab (pub/frama-c) issue
# '#@nnn' : Gitlab frama-c/frama-c issue #
# For compatibility with old change log formats: #
# '#nnn' : BTS entry #nnn (OBSOLETE) #
# '#!nnn' : BTS private entry #nnn (OBSOLETE) #
# '#?nnn' : OLD-BTS entry #nnn #
###############################################################################
......@@ -17,6 +18,8 @@
Open Source Release <next-release>
##################################
* Kernel [2022-02-08] Reject array whose size is too big with a proper
error message instead of a crash (fixes ##2590)
o! Kernel [2022-02-19] Removed obsolete AST nodes IndexPI and Info
o! Kernel [2021-12-03] Remove unused AST node Dcustom_annot and field
fpadding_in_bits. Do not cache size of types in the AST but in
......
......@@ -535,6 +535,7 @@ KERNEL_CMO=\
src/kernel_services/visitors/visitor_behavior.cmo \
src/kernel_services/ast_queries/cil.cmo \
src/kernel_services/ast_queries/cil_builtins.cmo \
src/kernel_internals/parsing/parse_env.cmo \
src/kernel_internals/parsing/errorloc.cmo \
src/kernel_services/ast_printing/cil_printer.cmo \
src/kernel_services/ast_printing/cil_descriptive_printer.cmo \
......
......@@ -742,6 +742,7 @@ check_plugin(from_analysis,src/plugins/from,[support for from analysis],yes)
plugin_require(from_analysis,eva)
plugin_require(from_analysis,callgraph)
plugin_require(from_analysis,postdominators)
# gui
#####
......@@ -807,6 +808,13 @@ plugin_require(pdg,callgraph)
check_plugin(postdominators,src/plugins/postdominators,
[support for postdominators plugin],yes)
# reduc
############
check_plugin(reduc,src/plugins/reduc,[support for reduc plugin],yes)
plugin_require(reduc,eva)
plugin_require(reduc,inout)
# rte
#####
......@@ -848,7 +856,7 @@ plugin_require(sparecode,users)
check_plugin(users,src/plugins/users,[support for users analysis],yes)
plugin_require(users,eva)
plugin_use(users,callgraph)
plugin_require(users,callgraph)
# value
#######
......
......@@ -948,6 +948,11 @@ e.g.:
Check \url{https://github.com/LexiFi/landmarks} for its documentation.
\textbf{Note:} if you intend to use \texttt{ocamlprof} (via \texttt{ocamlcp} or
\texttt{ocamloptp}), which does not support ppx extensions, and you have
Landmarks installed, you need to explicitly disable Landmarks during Frama-C's
configure: \verb+./configure --disable-landmarks+.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Local Variables:
%%% TeX-master: "developer.tex"
......
......@@ -281,7 +281,7 @@ a negative value, and choose the smallest rank possible starting from
that is, its opposite option \optiondef{-}{remove-unused-types} is set.
\item \texttt{\optiondef{-}{machdep} <machine architecture name>} defines the
target platform. The default value is a \texttt{x86\_32} bits
target platform. The default value is a \texttt{x86\_64} bits
platform. Analyzers may take into account the \emph{endianness} of the
target, the size and alignment of elementary data types, and other
architecture/compilation parameters. The \texttt{-machdep} option provides a
......
......@@ -3,5 +3,5 @@ int *t[2] = { &x, &y };
int main(void)
{
return 1 + (int) * (int*) ((int) t + 2);
return * (int*) ((unsigned long) t + 6);
}
......@@ -371,7 +371,7 @@ frama-c -eva main_1.c >log
\end{listing-nonumber}
Frama-C has its own model of the target platform (the default target is
a little-endian 32-bit platform). It also uses the host system's preprocessor.
a little-endian 64-bit platform). It also uses the host system's preprocessor.
If you want to do the analysis for a different platform than the host platform,
you need to provide Frama-C with a way to pre-process the files as they
would be during an actual compilation.
......@@ -579,7 +579,7 @@ use variable \lstinline|ONE| to detect endianness.
Frama-C assumes a little-endian architecture
by default, so \Eva{} is only analyzing the
little-endian version of the library (Frama-C
also assumes an IA-32 architecture, so we are only
also assumes an IA-64 architecture, so we are only
analyzing the library as compiled and run on this architecture).
The big-endian version of the library could be analyzed
by reproducing the same steps we are taking here for
......@@ -1349,14 +1349,14 @@ An example of a program leading to a misaligned read is the following:
\listinginput{1}{examples/misa.c}
The value returned by the function \lstinline|main| is\\
\lstinline|{{ garbled mix of &{ x; y } (origin: Misaligned { misa.c:6 }) }}|.\\
The analyzer is by default configured for a 32-bit architecture,
The analyzer is by default configured for a 64-bit architecture,
and that consequently the read memory access is not an out-of-bound access.
If it was, an alarm would be emitted, and the
analysis would go in a different direction.
With the default target platform, the read access remains
within the bounds of array \lstinline|t|,
but due to the offset of two bytes,
but due to the offset of six bytes,
the 32-bit word read is made of the last two bytes from \lstinline|t[0]|
and the first two bytes from \lstinline|t[1]|.
......
......@@ -395,6 +395,8 @@ src/kernel_internals/parsing/logic_lexer.mll: CEA_INRIA_LGPL
src/kernel_internals/parsing/logic_parser.mly: CEA_INRIA_LGPL
src/kernel_internals/parsing/logic_preprocess.mli: CEA_INRIA_LGPL
src/kernel_internals/parsing/logic_preprocess.mll: CEA_INRIA_LGPL
src/kernel_internals/parsing/parse_env.ml: CEA_LGPL
src/kernel_internals/parsing/parse_env.mli: CEA_LGPL
src/kernel_internals/runtime/README.md: .ignore
src/kernel_internals/runtime/boot.ml: CEA_LGPL
src/kernel_internals/runtime/boot.mli: CEA_LGPL
......@@ -1254,7 +1256,6 @@ src/plugins/security_slicing/security_slicing_parameters.mli: CEA_LGPL_OR_PROPRI
src/plugins/slicing/Slicing.mli: CEA_LGPL_OR_PROPRIETARY
src/plugins/slicing/api.ml: CEA_LGPL_OR_PROPRIETARY
src/plugins/slicing/api.mli: CEA_LGPL_OR_PROPRIETARY
src/plugins/slicing/bts336.c: .ignore
src/plugins/slicing/fct_slice.ml: CEA_LGPL_OR_PROPRIETARY
src/plugins/slicing/fct_slice.mli: CEA_LGPL_OR_PROPRIETARY
src/plugins/slicing/printSlice.ml: CEA_LGPL_OR_PROPRIETARY
......
......@@ -6,7 +6,6 @@ module.exports = {
'import',
],
extends: [
'airbnb-typescript',
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
......@@ -18,99 +17,67 @@ module.exports = {
},
settings: {
// Electron is in devDependencies because of its special build system
"import/core-modules": [ 'electron', 'react-hot-loader' ]
"import/core-modules": ['electron', 'react-hot-loader']
},
rules: {
// Do not enforce a displayName
"react/display-name": "off",
// Do not enforce component methods order
"react/sort-comp": "off",
// We do not use propTypes
"react/require-default-props": "off",
// Be more strict on usage of useMemo and useRef
"react-hooks/exhaustive-deps": "error",
// Allow type any, even if it should be avoided
"@typescript-eslint/no-explicit-any": "off",
// Allow functions without return type, even if exported function should have one
"@typescript-eslint/explicit-function-return-type": "off",
// Allow function hoisting, even if it should be avoided"
"@typescript-eslint/lines-between-class-members": "off",
"@typescript-eslint/space-before-function-paren": "off",
"@typescript-eslint/naming-convention": "off",
"no-constant-condition": ["error", { "checkLoops": false }],
"no-use-before-define": "off",
"@typescript-eslint/no-use-before-define": "off",
// Prefer const when _all_ destructured values may be const
"prefer-const": [
// --- Style rules ---
// Force code to 80 columns, but for trailing comments
"max-len": ["error", { "code": 80, "ignoreTrailingComments": true, }],
// Camelcase identifers
"camelcase": "error",
// Do not allow functions without return type, except function expressions (arrow functions)
"@typescript-eslint/explicit-function-return-type": [
"error",
{ "destructuring": "all", "ignoreReadBeforeAssign": false }
{
allowExpressions: true,
allowTypedFunctionExpressions: true,
allowConciseArrowFunctionExpressionsStartingWithVoid: true
}
],
// Allow declarations with char '_' as prefix/suffix
"no-underscore-dangle": "off",
// Allow return statements even if not strictly needed
"no-useless-return": "off",
// Forbid shadowing concerning variables
"no-shadow": "off",
// Force single class member per line
"lines-between-class-members": [
"error", "always", { "exceptAfterSingleLine": true }
],
// Allow blank line separators for complex blocks
"padded-blocks": "off",
// Allow braces on their own line
"@typescript-eslint/brace-style": "off",
// Already has built-in compiler checks in TSC for that
"@typescript-eslint/no-unused-vars": "off",
// Allow range conditions such as 0 <= x && x < 10
"yoda": [2, "never", { "onlyEquality": true }],
// Allow single command on new line after 'if' statement
"curly": "off",
// Do not specify position for single commands
"nonblock-statement-body-position": "off",
// Requires '+' to be applied on 2 numbers or 2 strings only
"@typescript-eslint/restrict-plus-operands": "error",
// Allow ++/-- operators only in for-loops
"no-plusplus": ["error", { "allowForLoopAfterthoughts": true }],
// Force code to 80 columns, but for trailing comments
"max-len": ["error", { "code": 80, "ignoreTrailingComments": true, }],
// Allow more than one class per file, even if not a good practice
"max-classes-per-file": "off",
// Allow assignment in return statements only with outer parenthesis
"no-return-assign": ["error", "except-parens" ],
// Allow single line expressions in react
"react/jsx-one-expression-per-line": "off",
// Allow property spreading since with aim at using TSC
"react/jsx-props-no-spreading": "off",
// Allow using functions in JSX props
"react/jsx-no-bind": "off",
// Allow all sorts of linebreaking for operators
"operator-linebreak": "off",
// Force curly brackets on newline if some item is
"object-curly-newline": ["error", { "multiline": true }],
// Allow non-destructed assignments
"react/destructuring-assignment": "off",
// Allow console errors and warnings
"no-console": ["error", { allow: ["warn", "error"] }],
// Disable accessibility rules
"jsx-a11y/label-has-associated-control": "off",
"jsx-a11y/click-events-have-key-events": "off",
"jsx-a11y/no-static-element-interactions": "off",
"jsx-a11y/no-noninteractive-element-interactions": "off",
"jsx-a11y/no-autofocus": "off",
// Completely broken rule
"react/prop-types": "off",
// Enable ++ and --
"no-plusplus": "off",
// Enable nested ternary operations
"no-nested-ternary": "off",
// Checked by TSC compiler
"default-case": "off",
"consistent-return": "off",
// Allow modify properties of object passed in parameter
"no-param-reassign": [ "error", { "props": false } ],
// Allow infinite loops but still disallow constant if-then-else
"no-constant-condition": ["error", { "checkLoops": false }],
// Prefer const including when destructuring when _all_ destructured values
// may be const
"prefer-const": [
"error",
{ "destructuring": "all", "ignoreReadBeforeAssign": false }
],
// Disallow the use of console.* to prevent the release of code producing
// various debuging messages
"no-console": "error",
// --- Safety rules ---
// Requires semicolon at the end of each statement to prevent
// misinterpretetion errors
"semi": "error",
// Be more strict on usage of useMemo and useRef
"react-hooks/exhaustive-deps": "error",
// Requires '+' to be applied on 2 numbers or 2 strings only
"@typescript-eslint/restrict-plus-operands": "error",
// Only use type safe comparison === as == between distinct type is not so obvious
"eqeqeq": "error",
// Disallow unused variables except variables starting with _
"no-unused-vars": "off", // Must be turned off for the following typescript rule
"@typescript-eslint/no-unused-vars": [
"error", {
"vars": "local",
"ignoreRestSiblings": true, // Useful to remove properties using rest properties
"varsIgnorePattern": "^_",
"argsIgnorePattern": "^_"
}
],
// Disallow the use of var in favor of let and const
"no-var": "error",
// Do not favor default import
"import/prefer-default-export": "off",
// Disallow explicit any types ; common workaround includes using 'unknown'
// when the type can't be infered
"@typescript-eslint/no-explicit-any": "error",
}
};
# Makefile Targets
The most useful developmenent targets are:
The most useful development targets are:
```
$ make tsc # run linter
......@@ -53,3 +53,88 @@ warnings. The same holds for React development.
Useful extensions:
- `ESlint` provides support for lint errors and warnings;
- `ES7 React/Redux/GraphQL/React-Native snippets` provides boilerplate snippets;
# Coding rules
Coding rules are mostly enforced by Eslint. It is mostly composed of all
recommended rules for typescript and React. A few of them are slightly weakened.
Additionally, a small set of rules have been added, divided in two categories.
1. *Safety rules*. These rules aim at avoiding errors by detecting common
mistakes early. Most of these rules have been added after finding a bug that
could have been avoided with this particular rule.
2. *Style rules*. These rules focus on code readability, including making things
explicit or ensuring uniformity. They should not be very constraining.
In some cases, trying to apply rules strictly might be counterproductive. It is
possible to deactivate rules locally with one of the following syntaxes.
```javascript
/* eslint-disable no-console */
console.log('test');
/* eslint-enable no-console */
```
```javascript
console.log('test'); // eslint-disable-line no-console
```
```javascript
// eslint-disable-next-line no-console
console.log('test');
```
## Safety rules
- [semi](https://eslint.org/docs/rules/semi).
Requires semicolon at the end of statements to avoid unexpected automatic
semicolon insertion.
- [react-hooks/exhaustive-deps](https://fr.reactjs.org/docs/hooks-rules.html#eslint-plugin).
Detect missing dependencies in hooks.
- [@typescript-eslint/restrict-plus-operands](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/restrict-plus-operands.md).
Forbids additions other than the addition of two numbers or the addition of
two strings. In other cases, implicit conversion might have unexpected
results. To conform to this rule, it might be necessary to use explicit
conversions or *template literals* (e.g. `` `N°${i}` ``).
- [eqeqeq](https://eslint.org/docs/rules/eqeqeq). Forces the use of `===`
instead of `==`. The latter often leads to unexpected comparisons in presence
of `undefined`, `null`, `false`, etc.
- [@typescript-eslint/no-unused-vars](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-unused-vars.md).
Forbids local variables and parameters which are declared but unused. It often
hides an error. Variables starting with `_` are ignored.
- [no-var](https://eslint.org/docs/rules/no-var).
Forces the usage of `let` or `const` instead of `var`, potentially avoiding
scoping errors.
- [@typescript-eslint/no-explicit-any](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-explicit-any.md).
Makes typing mandatory. `any` allows conversions from and into any type,
effectively disabling the type checker. `unknown` type can often be used
instead, but with the obligation to verify the actual type at runtime or
to use explicit unchecked conversions with `as`.
## Style rules
- [max-len](https://eslint.org/docs/rules/max-len).
Limit the lines to 80 columns, not including comments.
- [camelcase](https://eslint.org/docs/rules/camelcase).
Variable names uniformly use camelcase.
- [@typescript-eslint/explicit-function-return-type](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/explicit-function-return-type.md).
Function return type must always be given. This often helps understanding
the code. The rule is disabled for function expressions which can stay
concise.
- [lines-between-class-members](https://eslint.org/docs/rules/lines-between-class-members).
Forces empty lines between class members, except for single line declarations
(e.g. properties).
- [object-curly-newline](https://eslint.org/docs/rules/object-curly-newline).
Unify curly braces positions.
- [no-constant-condition](https://eslint.org/docs/rules/no-constant-condition).
Forbids constant conditions which are often used during the debug process but
should not remain in release versions. While recommended in Eslint, this
rule is weakened to allow infinite loops which make sense in Ivette.
- [prefer-const](https://eslint.org/docs/rules/prefer-const).
Whenever possible, prefer `const`. Systematic use of `const` makes mutations
easier to spot and may help to identify problems early.
- [no-console](https://eslint.org/docs/rules/no-console).
Forbids the use of `console.*` to prevent remaining debug outputs in code
releases. For error printing in the console, the use of Dome.Debug is
encouraged.
......@@ -172,7 +172,6 @@ DISTRIB_FILES += ivette/src/frama-c/plugins/dive/pkg.json
DISTRIB_FILES += ivette/src/frama-c/plugins/dive/react-cytoscapejs.d.ts
DISTRIB_FILES += ivette/src/frama-c/plugins/dive/style.json
DISTRIB_FILES += ivette/src/frama-c/plugins/dive/tippy.css
DISTRIB_FILES += ivette/src/frama-c/plugins/eva/.eslintrc.js
DISTRIB_FILES += ivette/src/frama-c/plugins/eva/Coverage.tsx
DISTRIB_FILES += ivette/src/frama-c/plugins/eva/CoverageMeter.tsx
DISTRIB_FILES += ivette/src/frama-c/plugins/eva/Summary.tsx
......
......@@ -172,7 +172,6 @@ src/frama-c/plugins/dive/pkg.json: .ignore
src/frama-c/plugins/dive/react-cytoscapejs.d.ts: CEA_LGPL
src/frama-c/plugins/dive/style.json: .ignore
src/frama-c/plugins/dive/tippy.css: .ignore
src/frama-c/plugins/eva/.eslintrc.js: .ignore
src/frama-c/plugins/eva/Coverage.tsx: CEA_LGPL
src/frama-c/plugins/eva/CoverageMeter.tsx: CEA_LGPL
src/frama-c/plugins/eva/Summary.tsx: CEA_LGPL
......
......@@ -20,6 +20,9 @@
/* */
/* ************************************************************************ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable no-console */
/**
## Dome Application (Main Process)
......@@ -136,7 +139,7 @@ function obtainGlobalSettings() {
// --- Window Settings & Frames
// --------------------------------------------------------------------------
type Store = { [key: string]: any };
type Store = { [key: string]: unknown };
interface Handle {
window: BrowserWindow; // Also prevents Gc
......@@ -175,7 +178,7 @@ ipcMain.on('dome.ipc.settings.sync', windowSyncSettings);
// --- Patching Settings
// --------------------------------------------------------------------------
type Patch = { key: string; value: any };
type Patch = { key: string; value: unknown };
function applyPatches(data: Store, args: Patch[]) {
args.forEach(({ key, value }) => {
......@@ -222,7 +225,7 @@ ipcMain.on('dome.ipc.settings.storage', applyStorageSettings);
// --- Renderer-Process Communication
// --------------------------------------------------------------------------
function broadcast(event: string, ...args: any[]) {
function broadcast(event: string, ...args: unknown[]) {
BrowserWindow.getAllWindows().forEach((w) => {
w.webContents.send(event, ...args);
});
......@@ -340,7 +343,7 @@ function createBrowserWindow(
const { frame, devtools, settings = {}, storage = {} } = configData;
if (frame) {
const getInt = (v: any) => v && _.toSafeInteger(v);
const getInt = <A>(v: A) => v && _.toSafeInteger(v);
options.x = getInt(frame.x);
options.y = getInt(frame.y);
options.width = getInt(frame.width);
......
......@@ -20,6 +20,9 @@
/* */
/* ************************************************************************ */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable no-console */
// --------------------------------------------------------------------------
// --- Menus & MenuBar Management
// --------------------------------------------------------------------------
......
......@@ -26,6 +26,7 @@
*/
/* eslint-disable max-len */
/* eslint-disable no-console */
// --------------------------------------------------------------------------
// --- Evolved Spawn Process
......@@ -98,12 +99,12 @@ const exitJobs: Callback[] = [];
Exceptions thrown by the function are captured and reported on the console.
*/
export function atExit(callback: Callback) {
export function atExit(callback: Callback): void {
exitJobs.push(callback);
}
/** Execute all pending exit jobs (and flush the list). */
export function doExit() {
export function doExit(): void {
exitJobs.forEach((fn) => {
try { fn(); }
catch (err) { console.error('[Dome] atExit:', err); }
......@@ -118,7 +119,7 @@ export function doExit() {
let COMMAND_WDIR = '.';
let COMMAND_ARGV: string[] = [];
function setCommandLine(argv: string[], wdir: string) {
function setCommandLine(argv: string[], wdir: string): void {
COMMAND_ARGV = argv;
COMMAND_WDIR = wdir;
}
......@@ -134,12 +135,12 @@ function setCommandLine(argv: string[], wdir: string) {
See also [[dome.onCommand]]
*/
export function getWorkingDir() { return COMMAND_WDIR; }
export function getWorkingDir(): string { return COMMAND_WDIR; }
/**
Returns the current process ID.
*/
export function getPID() { return process.pid; }
export function getPID(): number { return process.pid; }
/**
Command-line arguments (Application Window).
......@@ -151,7 +152,7 @@ export function getPID() { return process.pid; }
See also [[dome.onCommand]]
*/
export function getArguments() { return COMMAND_ARGV; }
export function getArguments(): string[] { return COMMAND_ARGV; }
// --------------------------------------------------------------------------
// --- File Join
......@@ -232,9 +233,9 @@ export function fileStat(path: string): Promise<fs.Stats> {
Checks if a path exists and is a regular file
(Synchronous check).
*/
export function isFile(path: string) {
export function isFile(path: string): boolean {
try {
return path && fs.statSync(path).isFile();
return !!path && fs.statSync(path).isFile();
} catch (_err) {
return false;
}
......@@ -244,9 +245,9 @@ export function isFile(path: string) {
Checks if a path exists and is a directory
(Synchronous check).
*/
export function isDirectory(path: string) {
export function isDirectory(path: string): boolean {
try {
return path && fs.statSync(path).isDirectory();
return !!path && fs.statSync(path).isDirectory();
} catch (_err) {
return false;
}
......@@ -256,7 +257,7 @@ export function isDirectory(path: string) {
Checks if a path exists and is a file or directory
(Synchronous check).
*/
export function exists(path: string) {
export function exists(path: string): boolean {
try {
if (!path) return false;
const stats = fs.statSync(path);
......@@ -321,7 +322,7 @@ export async function copyFile(srcPath: string, tgtPath: string): Promise<void>
On MacOS, `.DS_Store` entries are filtered out.
*/
export async function readDir(path: string): Promise<string[]> {
const filterDir = (f: string) => f !== '.DS_Store';
const filterDir = (f: string): boolean => f !== '.DS_Store';
const entries = await fs.promises.readdir(path, { encoding: 'utf-8', withFileTypes: true });
return entries.map((fn) => fn.name).filter(filterDir);
}
......@@ -389,7 +390,7 @@ async function rmDirRec(path: string): Promise<void> {
return;
}
if (stats.isDirectory()) {
const rmDirSub = (name: string) => {
const rmDirSub = (name: string): void => {
rmDirRec(fspath.join(path, name));
};
const entries = await readDir(path);
......@@ -476,7 +477,7 @@ interface Readable {
unpipe(out: fs.WriteStream): void;
}
function pipeTee(std: Readable, fd: number) {
function pipeTee(std: Readable, fd: number): void {
if (!fd) return;
const out = fs.createWriteStream('<ignored>', { fd, encoding: 'utf-8' });
out.on('error', (err) => {
......
......@@ -38,7 +38,7 @@ interface EVENT {
stopPropagation: () => void;
}
const DISABLED = ({ disabled = false, enabled = true }) => (
const DISABLED = ({ disabled = false, enabled = true }): boolean => (
!!disabled || !enabled
);
......@@ -59,7 +59,7 @@ interface LABELprops {
label: string;
}
const LABEL = ({ disabled, label }: LABELprops) => (
const LABEL = ({ disabled, label }: LABELprops): JSX.Element => (
<div className="dome-xButton-label">
<div
className="dome-xButton-label dome-control-enabled"
......@@ -122,7 +122,7 @@ export interface ButtonProps {
}
/** Standard button. */
export function Button(props: ButtonProps) {
export function Button(props: ButtonProps): JSX.Element {
const disabled = props.onClick ? DISABLED(props) : true;
const {
focusable = false, kind = 'default',
......@@ -160,7 +160,7 @@ export function Button(props: ButtonProps) {
// --------------------------------------------------------------------------
/** Circled Icon Button. The label property is ignored. */
export const CircButton = (props: ButtonProps) => {
export const CircButton = (props: ButtonProps): JSX.Element => {
const disabled = props.onClick ? DISABLED(props) : true;
const {
focusable = false, kind = 'default',
......@@ -238,7 +238,7 @@ export interface IconButtonProps {
}
/** Borderless Icon Button. Label property is ignored. */
export function IconButton(props: IconButtonProps) {
export function IconButton(props: IconButtonProps): JSX.Element | null {
const disabled = props.onClick ? DISABLED(props) : true;
const {
icon, title, className,
......@@ -294,7 +294,7 @@ export interface CheckProps {
}
/** Checkbox button. */
export const Checkbox = (props: CheckProps) => {
export const Checkbox = (props: CheckProps): JSX.Element => {
const { value, onChange } = props;
const disabled = onChange ? DISABLED(props) : true;
const callback = onChange && (() => onChange(!value));
......@@ -318,7 +318,7 @@ export const Checkbox = (props: CheckProps) => {
};
/** Switch button. */
export const Switch = (props: CheckProps) => {
export const Switch = (props: CheckProps): JSX.Element => {
const { onChange, value } = props;
const disabled = onChange ? DISABLED(props) : true;
const iconId = props.value ? 'SWITCH.ON' : 'SWITCH.OFF';
......@@ -367,7 +367,7 @@ export interface RadioProps<A> {
}
/** Radio Button. See also [[RadioGroup]]. */
export function Radio<A>(props: RadioProps<A>) {
export function Radio<A>(props: RadioProps<A>): JSX.Element {
const { onSelection, value, selection } = props;
const disabled = onSelection ? DISABLED(props) : true;
const checked = value === selection;
......@@ -427,7 +427,7 @@ export interface RadioGroupProps<A> {
The radio buttons inside a group are laidout in a vertical box with the
additional styling properties.
*/
export function RadioGroup<A>(props: RadioGroupProps<A>) {
export function RadioGroup<A>(props: RadioGroupProps<A>): JSX.Element {
const {
className = '',
style,
......@@ -435,15 +435,16 @@ export function RadioGroup<A>(props: RadioGroupProps<A>) {
onChange: onGroupSelect,
} = props;
const disabledGroup = onGroupSelect ? DISABLED(props) : true;
const makeRadio = (elt: any) => {
const radioProps = elt.props as RadioProps<A>;
const makeRadio = (elt: unknown): JSX.Element => {
const typedElt = elt as React.ReactElement<RadioProps<A>>;
const radioProps = typedElt.props;
const disabled = disabledGroup || DISABLED(radioProps);
const { onSelection: onRadioSelect } = radioProps;
const onSelection = (v: A) => {
const onSelection = (v: A): void => {
if (onRadioSelect) onRadioSelect(v);
if (onGroupSelect) onGroupSelect(v);
};
return React.cloneElement(elt, {
return React.cloneElement(typedElt, {
disabled,
enabled: !disabled,
selection,
......@@ -495,14 +496,14 @@ export interface SelectProps {
* <option value='…' disabled=… >…</option>
*/
export function Select(props: SelectProps) {
export function Select(props: SelectProps): JSX.Element {
const { onChange, placeholder } = props;
const className = classes(
'dome-xSelect dome-xBoxButton dome-xButton-default dome-xButton-label',
props.className,
);
const disabled = onChange ? DISABLED(props) : true;
const callback = (evt: React.ChangeEvent<HTMLSelectElement>) => {
const callback = (evt: React.ChangeEvent<HTMLSelectElement>): void => {
if (onChange) onChange(evt.target.value);
};
return (
......@@ -553,17 +554,17 @@ export interface FieldProps {
/**
Text Field.
*/
export const Field = (props: FieldProps) => {
export const Field = (props: FieldProps): JSX.Element => {
const [current, setCurrent] = React.useState<string>();
const { className = '', onChange, onEdited, value = '' } = props;
const disabled = onChange ? DISABLED(props) : true;
const theValue = current ?? value;
const ONCHANGE = (evt: React.ChangeEvent<HTMLInputElement>) => {
const ONCHANGE = (evt: React.ChangeEvent<HTMLInputElement>): void => {
const text = evt.target.value || '';
setCurrent(text);
if (onEdited) onEdited(text);
};
const ONKEYPRESS = (evt: React.KeyboardEvent) => {
const ONKEYPRESS = (evt: React.KeyboardEvent): void => {
switch (evt.key) {
case 'Enter':
setCurrent(undefined);
......
......@@ -40,7 +40,7 @@ import './style.css';
// --------------------------------------------------------------------------
/** Button-like label. */
export function LCD(props: LabelProps) {
export function LCD(props: LabelProps): JSX.Element {
const className = classes(
'dome-xButton dome-xBoxButton dome-text-code dome-xButton-lcd ',
props.className,
......@@ -85,7 +85,7 @@ export interface LEDprops {
style?: React.CSSProperties;
}
export const LED = (props: LEDprops) => {
export const LED = (props: LEDprops): JSX.Element => {
const className = classes(
'dome-xButton-led',
`dome-xButton-led-${props.status || 'inactive'}`,
......@@ -116,7 +116,7 @@ export interface MeterProps {
optimum?: number | 'LOW' | 'MEDIUM' | 'HIGH'; /** default is undefined */
}
export const Meter = (props: MeterProps) => {
export const Meter = (props: MeterProps): JSX.Element => {
const { className, style, value, optimum, ...ms } = props;
const min = props.min ?? 0.0;
const max = props.max ?? 1.0;
......
......@@ -109,7 +109,7 @@ export interface IconProps extends SVGprops {
Icon Component.
Consult the [Icon Gallery](../guides/icons.md.html) for default icons.
*/
export function Icon(props: IconProps) {
export function Icon(props: IconProps): JSX.Element {
const {
id, title, onClick, fill,
size, className = '', offset, style,
......@@ -150,7 +150,7 @@ export interface BadgeProps {
a label, or the corresponding named icon.
Consult the [Icon Gallery](gallery-icons.html) for default icons.
*/
export function Badge(props: BadgeProps) {
export function Badge(props: BadgeProps): JSX.Element {
const { value, title, onClick } = props;
let content;
if (typeof value === 'string' && Icons[value]) {
......@@ -190,7 +190,7 @@ export interface CustomIcon {
/**
Register a new custom icon.
*/
export function register(icon: CustomIcon) {
export function register(icon: CustomIcon): void {
const { id, ...jsicon } = icon;
Icons[id] = jsicon;
}
......@@ -199,7 +199,7 @@ export function register(icon: CustomIcon) {
Iterate over icons gallery.
See [[register]] to add custom icons to the gallery.
*/
export function forEach(fn: (ico: CustomIcon) => void) {
export function forEach(fn: (ico: CustomIcon) => void): void {
const ids = Object.keys(Icons);
ids.forEach((id) => {
const jsicon = Icons[id];
......
......@@ -29,7 +29,7 @@
@module dome/controls/labels
*/
import React from 'react';
import React, { LegacyRef } from 'react';
import { classes } from 'dome/misc/utils';
import { Icon } from './icons';
import './style.css';
......@@ -62,29 +62,34 @@ export interface LabelProps {
onContextMenu?: (evt: React.MouseEvent) => void;
}
const makeLabel = (className: string) => (props: LabelProps, ref: any) => {
const { display = true } = props;
const allClasses = classes(
className,
!display && 'dome-control-erased',
props.className,
);
return (
<label
ref={ref}
className={allClasses}
title={props.title}
style={props.style}
onClick={props.onClick}
onDoubleClick={props.onDoubleClick}
onContextMenu={props.onContextMenu}
>
{props.icon && <Icon title={props.title} id={props.icon} />}
{props.label}
{props.children}
</label>
);
};
const makeLabel = (className: string) =>
function Label
(
props: LabelProps,
ref: LegacyRef<HTMLLabelElement> | undefined
): JSX.Element {
const { display = true } = props;
const allClasses = classes(
className,
!display && 'dome-control-erased',
props.className,
);
return (
<label
ref={ref}
className={allClasses}
title={props.title}
style={props.style}
onClick={props.onClick}
onDoubleClick={props.onDoubleClick}
onContextMenu={props.onContextMenu}
>
{props.icon && <Icon title={props.title} id={props.icon} />}
{props.label}
{props.children}
</label>
);
};
// --------------------------------------------------------------------------
// --- CSS Classes
......