Skip to content

Commit

Permalink
Add prettier formatting for www (apache#29768)
Browse files Browse the repository at this point in the history
* Add prettier formatter for www

* Ignore markdown as formatted by eslint

* Fix CI

* Update CONTRIBUTING.rst
  • Loading branch information
pierrejeambrun authored Feb 27, 2023
1 parent df4abcb commit 0db38ad
Show file tree
Hide file tree
Showing 169 changed files with 6,634 additions and 4,964 deletions.
1 change: 1 addition & 0 deletions .codespellignorelines
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
roles = relationship("Role", secondary=assoc_user_role, backref="user", lazy="selectin")
The platform supports **C**reate, **R**ead, **U**pdate, and **D**elete operations on most resources.
<pre><code>Code block\ndoes not\nrespect\nnewlines\n</code></pre>
"trough",
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ repos:
language: node
files: ^airflow/www/.*\.(css|sass|scss)$
# Keep dependency versions in sync w/ airflow/www/package.json
additional_dependencies: ['[email protected]', '[email protected]']
additional_dependencies: ['[email protected]', '[email protected]', '[email protected]']
- id: compile-www-assets
name: Compile www assets
language: node
Expand Down Expand Up @@ -877,10 +877,10 @@ repos:
additional_dependencies: ['rich>=12.4.4']
pass_filenames: false
files: ^tests/.*\.py$
- id: ts-compile-and-lint-javascript
name: TS types generation and ESLint against current UI files
- id: ts-compile-format-lint-www
name: TS types generation and ESLint/Prettier against current UI files
language: node
'types_or': [javascript, ts, tsx, yaml]
'types_or': [javascript, ts, tsx, yaml, css, json]
files: ^airflow/www/static/js/|^airflow/api_connexion/openapi/v1\.yaml$
entry: ./scripts/ci/pre_commit/pre_commit_www_lint.py
additional_dependencies: ['[email protected]']
Expand Down
4 changes: 3 additions & 1 deletion .rat-excludes
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
.coveragerc
.codecov.yml
.codespellignorelines
.eslintrc
.eslintignore
.eslintrc
.prettierignore
.prettierrc
.rat-excludes
.stylelintignore
.stylelintrc
Expand Down
21 changes: 12 additions & 9 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1179,29 +1179,32 @@ commands:
yarn run dev
Follow JavaScript Style Guide
-----------------------------
Follow Style Guide
------------------

We try to enforce a more consistent style and follow the JS community
We try to enforce a more consistent style and follow the Javascript/Typescript community
guidelines.

Once you add or modify any JavaScript code in the project, please make sure it
Once you add or modify any JS/TS code in the project, please make sure it
follows the guidelines defined in `Airbnb
JavaScript Style Guide <https://github.com/airbnb/javascript>`__.

Apache Airflow uses `ESLint <https://eslint.org/>`__ as a tool for identifying and
reporting on patterns in JavaScript. To use it, run any of the following
commands:
reporting issues in JS/TS, and `Prettier <https://prettier.io/>`__ for code formatting.
Most IDE directly integrate with these tools, you can also manually run them with any of the following commands:

.. code-block:: bash
# Check JS code in .js, .jsx, and .html files, and report any errors/warnings
# Format code in .js, .jsx, .ts, .tsx, .json, .css, .html files
yarn format
# Check JS/TS code in .js, .jsx, .ts, .tsx, .html files and report any errors/warnings
yarn run lint
# Check JS code in .js, .jsx, and .html files, report any errors/warnings and fix them if possible
# Check JS/TS code in .js, .jsx, .ts, .tsx, .html files and report any errors/warnings and fix them if possible
yarn run lint:fix
# Runs tests for all .test.js and .test.jsx files
# Run tests for all .test.js, .test.jsx, .test.ts, test.tsx files
yarn test
React, JSX and Chakra
Expand Down
2 changes: 1 addition & 1 deletion STATIC_CODE_CHECKS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ require Breeze Docker image to be build locally.
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
| trailing-whitespace | Remove trailing whitespace at end of line | |
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
| ts-compile-and-lint-javascript | TS types generation and ESLint against current UI files | |
| ts-compile-format-lint-www | TS types generation and ESLint/Prettier against current UI files | |
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
| update-black-version | Update black versions everywhere | |
+-----------------------------------------------------------+------------------------------------------------------------------+---------+
Expand Down
18 changes: 10 additions & 8 deletions airflow/www/.eslintrc
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
{
"extends": ["airbnb", "airbnb/hooks"],
"extends": ["airbnb", "airbnb/hooks", "prettier"],
"parser": "@babel/eslint-parser",
"parserOptions": {
"babelOptions": {
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"],
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript"
],
"plugins": ["@babel/plugin-transform-runtime"]
}
},
"plugins": [ "html", "react" ],
"plugins": ["html", "react"],
"rules": {
"no-param-reassign": 1,
"react/prop-types": 0,
Expand All @@ -21,7 +25,7 @@
"ts": "never",
"tsx": "never"
}
],
],
"import/no-extraneous-dependencies": [
"error",
{
Expand All @@ -48,11 +52,9 @@
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"extends": [
"airbnb-typescript"
],
"extends": ["airbnb-typescript", "prettier"],
"parser": "@typescript-eslint/parser",
"plugins": [ "@typescript-eslint" ],
"plugins": ["@typescript-eslint"],
"parserOptions": {
"project": "./tsconfig.json"
},
Expand Down
5 changes: 5 additions & 0 deletions airflow/www/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.mypy_cache/
templates/**/*.html
dist/
*.md
*.yaml
10 changes: 10 additions & 0 deletions airflow/www/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"overrides": [
{
"files": "*.json",
"options": {
"tabWidth": 2
}
}
]
}
2 changes: 1 addition & 1 deletion airflow/www/.stylelintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "stylelint-config-standard"
"extends": ["stylelint-config-standard", "stylelint-config-prettier"]
}
120 changes: 76 additions & 44 deletions airflow/www/alias-rest-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
* under the License.
*/

const ts = require('typescript');
const fs = require('fs');
const ts = require("typescript");
const fs = require("fs");

/* This library does three things to make openapi-typescript generation easier to use.
* 1. Creates capitalized exports for Paths and Operations
Expand All @@ -29,16 +29,16 @@ const fs = require('fs');
*/

/* Finds all words, capitalizes them, and removes all other characters. */
const toPascalCase = (str) => (
const toPascalCase = (str) =>
(str.match(/[a-zA-Z0-9]+/g) || [])
.map((w) => `${w.charAt(0).toUpperCase()}${w.slice(1)}`)
.join('')
);
.join("");

/* Adds a prefix to a type prop as necessary.
* ('', 'components') => 'components'
*/
const prefixPath = (rootPrefix, prop) => (rootPrefix ? `${rootPrefix}['${prop}']` : prop);
const prefixPath = (rootPrefix, prop) =>
rootPrefix ? `${rootPrefix}['${prop}']` : prop;

// Recursively find child nodes by name.
const findNode = (node, ...names) => {
Expand All @@ -58,87 +58,114 @@ const findNode = (node, ...names) => {
// Generate Variable Type Aliases for a given path or operation
const generateVariableAliases = (node, operationPath, operationName) => {
const variableTypes = [];
const hasPath = !!findNode(node, 'parameters', 'path');
const hasQuery = !!findNode(node, 'parameters', 'query');
const hasBody = !!findNode(node, 'requestBody', 'content', 'application/json');
const hasPath = !!findNode(node, "parameters", "path");
const hasQuery = !!findNode(node, "parameters", "query");
const hasBody = !!findNode(
node,
"requestBody",
"content",
"application/json"
);

if (hasPath) variableTypes.push(`${operationPath}['parameters']['path']`);
if (hasQuery) variableTypes.push(`${operationPath}['parameters']['query']`);
if (hasBody) variableTypes.push(`${operationPath}['requestBody']['content']['application/json']`);
if (hasBody)
variableTypes.push(
`${operationPath}['requestBody']['content']['application/json']`
);

if (variableTypes.length === 0) return '';
if (variableTypes.length === 0) return "";
const typeName = `${toPascalCase(operationName)}Variables`;
return [typeName, `export type ${typeName} = CamelCasedPropertiesDeep<${variableTypes.join(' & ')}>;`];
return [
typeName,
`export type ${typeName} = CamelCasedPropertiesDeep<${variableTypes.join(
" & "
)}>;`,
];
};

// Generate Type Aliases
const generateAliases = (rootNode, writeText, prefix = '') => {
const generateAliases = (rootNode, writeText, prefix = "") => {
// Loop through the root AST nodes of the file
ts.forEachChild(rootNode, (node) => {
// Response Data Types
if (ts.isInterfaceDeclaration(node) && node.name?.text === 'components') {
const schemaMemberNames = findNode(node, 'schemas').type.members.map((n) => n.name?.text);
if (ts.isInterfaceDeclaration(node) && node.name?.text === "components") {
const schemaMemberNames = findNode(node, "schemas").type.members.map(
(n) => n.name?.text
);

const types = schemaMemberNames.map((n) => [
`${n}`,
`export type ${n} = CamelCasedPropertiesDeep<${prefixPath(prefix, 'components')}['schemas']['${n}']>;`,
`export type ${n} = CamelCasedPropertiesDeep<${prefixPath(
prefix,
"components"
)}['schemas']['${n}']>;`,
]);
if (types.length) {
writeText.push(['comment', `Types for returned data ${prefix}`]);
writeText.push(["comment", `Types for returned data ${prefix}`]);
writeText.push(...types);
}
}

// Paths referencing an operation are skipped
if (node.name?.text === 'paths') {
if (node.name?.text === "paths") {
if (!prefix) {
writeText.push(['comment', 'Alias paths to PascalCase.']);
writeText.push(['Paths', 'export type Paths = paths;']);
writeText.push(["comment", "Alias paths to PascalCase."]);
writeText.push(["Paths", "export type Paths = paths;"]);
}

const types = [];

(node.members || node.type.members).forEach((path) => {
const methodNames = path.type.members.map((m) => m.name.text);
const methodTypes = methodNames.map((m) => (
const methodTypes = methodNames.map((m) =>
generateVariableAliases(
findNode(path, m),
`${prefixPath(prefix, 'paths')}['${path.name?.text}']['${m}']`,
`${path.name.text}${toPascalCase(m)}`,
)));
`${prefixPath(prefix, "paths")}['${path.name?.text}']['${m}']`,
`${path.name.text}${toPascalCase(m)}`
)
);
types.push(...methodTypes.filter((m) => !!m));
});

if (types.length) {
writeText.push(['comment', `Types for path operation variables ${prefix}`]);
writeText.push([
"comment",
`Types for path operation variables ${prefix}`,
]);
writeText.push(...types);
}
}

// operationIds are defined
if (node.name?.text === 'operations') {
if (node.name?.text === "operations") {
if (!prefix) {
writeText.push(['comment', 'Alias operations to PascalCase.']);
writeText.push(['Operations', 'export type Operations = operations;']);
writeText.push(["comment", "Alias operations to PascalCase."]);
writeText.push(["Operations", "export type Operations = operations;"]);
}

const types = (node.members || node.type.members).map((operation) => (
const types = (node.members || node.type.members).map((operation) =>
generateVariableAliases(
operation,
`${prefixPath(prefix, 'operations')}['${operation.name.text}']`,
operation.name.text,
)));
`${prefixPath(prefix, "operations")}['${operation.name.text}']`,
operation.name.text
)
);
if (types.length) {
writeText.push(['comment', `Types for operation variables ${prefix}`]);
writeText.push(["comment", `Types for operation variables ${prefix}`]);
writeText.push(...types);
writeText.push('\n');
writeText.push("\n");
}
}

// recursively call this for any externals
if (ts.isInterfaceDeclaration(node) && node.name?.text === 'external') {
if (ts.isInterfaceDeclaration(node) && node.name?.text === "external") {
node.members.forEach((external) => {
generateAliases(external.type, writeText, `external['${external.name.text}']`);
generateAliases(
external.type,
writeText,
`external['${external.name.text}']`
);
});
}
});
Expand Down Expand Up @@ -169,27 +196,32 @@ function generate(file) {
const program = ts.createProgram([file], { allowJs: true });
const sourceFile = program.getSourceFile(file);
const writeText = [];
writeText.push(['block', license]);
writeText.push(['comment', 'eslint-disable']);
writeText.push(["block", license]);
writeText.push(["comment", "eslint-disable"]);
// eslint-disable-next-line quotes
writeText.push(['block', `import type { CamelCasedPropertiesDeep } from 'type-fest';`]);
writeText.push(['block', sourceFile.text]);
writeText.push([
"block",
`import type { CamelCasedPropertiesDeep } from 'type-fest';`,
]);
writeText.push(["block", sourceFile.text]);
generateAliases(sourceFile, writeText);

const finalText = writeText
// Deduplicate types
.map((pair) => {
// keep all comments and code blocks
if (pair[0] === 'comment' || pair[0] === 'block') return pair;
if (pair[0] === "comment" || pair[0] === "block") return pair;
// return the first instance of this key only
const firstInstance = writeText.find((p) => p[0] === pair[0]);
return firstInstance === pair ? pair : ['comment', `Duplicate removed: ${pair[1]}`];
return firstInstance === pair
? pair
: ["comment", `Duplicate removed: ${pair[1]}`];
})
// Remove undefined created above
.filter((p) => !!p)
// Escape comments and flatten.
.map((pair) => (pair[0] === 'comment' ? `\n/* ${pair[1]} */` : pair[1]))
.join('\n');
.map((pair) => (pair[0] === "comment" ? `\n/* ${pair[1]} */` : pair[1]))
.join("\n");

fs.writeFileSync(file, finalText, (err) => {
if (err) {
Expand Down
8 changes: 6 additions & 2 deletions airflow/www/babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
module.exports = function (api) {
api.cache(true);

const presets = ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'];
const presets = [
"@babel/preset-env",
"@babel/preset-react",
"@babel/preset-typescript",
];

const plugins = ['@babel/plugin-transform-runtime'];
const plugins = ["@babel/plugin-transform-runtime"];

return {
presets,
Expand Down
Loading

0 comments on commit 0db38ad

Please sign in to comment.