Compare commits

...

2 Commits

Author SHA1 Message Date
dbd5ae90eb web: Remove escape. 2025-06-27 00:18:12 +02:00
40363a2142 web: Flesh out import clean up. 2025-06-26 23:52:54 +02:00
4 changed files with 1812 additions and 245 deletions

View File

@ -2,8 +2,11 @@
* @file Prettier configuration for authentik.
*
* @import { Config as PrettierConfig } from "prettier";
* @import { PluginConfig as SortPluginConfig } from "@trivago/prettier-plugin-sort-imports";
*
*/
import { importsPlugin } from "./imports.js";
/**
* @typedef {object} PackageJSONPluginConfig
* @property {string[]} [packageSortOrder] Custom ordering array.
*/
@ -11,7 +14,7 @@
/**
* authentik Prettier configuration.
*
* @type {PrettierConfig & SortPluginConfig & PackageJSONPluginConfig}
* @type {PrettierConfig & PackageJSONPluginConfig}
* @internal
*/
export const AuthentikPrettierConfig = {
@ -34,32 +37,8 @@ export const AuthentikPrettierConfig = {
plugins: [
// ---
"prettier-plugin-packagejson",
"@trivago/prettier-plugin-sort-imports",
importsPlugin(),
],
importOrder: [
// ---
"^(@goauthentik/|#)common.+",
"^(@goauthentik/|#)elements.+",
"^(@goauthentik/|#)components.+",
"^(@goauthentik/|#)user.+",
"^(@goauthentik/|#)admin.+",
"^(@goauthentik/|#)flow.+",
"^#.+",
"^@goauthentik.+",
"<THIRD_PARTY_MODULES>",
"^(@?)lit(.*)$",
"\\.css$",
"^@goauthentik/api$",
"^[./]",
],
importOrderSideEffects: false,
importOrderSeparation: true,
importOrderSortSpecifiers: true,
importOrderParserPlugins: ["typescript", "jsx", "classProperties", "decorators-legacy"],
overrides: [
{
files: "schemas/**/*.json",

View File

@ -0,0 +1,172 @@
import { createRequire } from "node:module";
import { formatSourceFromFile } from "format-imports";
import { parsers as babelParsers } from "prettier/plugins/babel";
/**
* @file Prettier import plugin.
*
* @import { Plugin, ParserOptions } from "prettier";
*/
import { parsers as typescriptParsers } from "prettier/plugins/typescript";
const require = createRequire(process.cwd() + "/");
/**
* @param {string} name
* @returns {string | null}
*/
function resolveModule(name) {
try {
return require.resolve(name);
} catch (error) {
return null;
}
}
const webSubmodules = [
// ---
"common",
"elements",
"components",
"user",
"admin",
"flow",
];
/**
* Ensure that every import without an extension adds one.
* @param {string} input
* @returns {string}
*/
function normalizeExtensions(input) {
return input.replace(/(?:import|from)\s*["']((?:\.\.?\/).*?)(?<!\.\w+)["']/gm, (line, path) => {
return line.replace(path, `${path}.js`);
});
}
/**
* @param {string} filepath
* @param {string} input
* @returns {string}
*/
function normalizeImports(filepath, input) {
let output = input;
// Replace all TypeScript imports with the paths resolved by Node/Browser import maps.
for (const submodule of webSubmodules) {
const legacyPattern = new RegExp(
[
// ---
`(?:import|from)`,
`\\\(?\\n?\\s*`,
`"(?<suffix>@goauthentik\/${submodule}\/)`,
`(?<path>[^"'.]+)`,
`(?:.[^"']+)?["']`,
`\\n?\\s*\\\)?;`,
].join(""),
"gm",
);
output = output.replace(
legacyPattern,
/**
* @param {string} line
* @param {string} suffix
* @param {string} path
*/
(line, suffix, path) => {
const exported = `@goauthentik/web/${submodule}/${path}`;
let imported = `#${submodule}/${path}`;
let module = resolveModule(`${exported}.ts`);
if (!module) {
module = resolveModule(`${exported}/index.ts`);
imported += "/index";
}
if (imported.endsWith(".css")) {
imported += ".js";
}
if (!module) {
console.warn(`\nCannot resolve module ${exported} from ${filepath}`, {
line,
path,
exported,
imported,
module,
});
process.exit(1);
}
return (
line
// ---
.replace(suffix + path, imported)
.replace(`${imported}.js`, imported)
);
},
);
}
return output;
}
/**
* @returns {Plugin}
*/
export function importsPlugin({
useLegacyCleanup = process.env.AK_FIX_LEGACY_IMPORTS === "true",
} = {}) {
/**
* @param {string} input
* @param {ParserOptions} options
*/
const preprocess = (input, { filepath, printWidth }) => {
let output = input;
if (useLegacyCleanup) {
output = normalizeExtensions(input);
output = normalizeImports(filepath, output);
}
const value = formatSourceFromFile.sync(output, filepath, {
nodeProtocol: "always",
maxLineLength: printWidth,
wrappingStyle: "prettier",
groupRules: [
"^node:",
...webSubmodules.map((submodule) => `^(@goauthentik/|#)${submodule}.+`),
"^#.+",
"^@goauthentik.+",
{}, // Other imports.
"^(@?)lit(.*)$",
"\\.css$",
"^@goauthentik/api$",
"^[./]",
],
});
return value || input;
};
return {
parsers: {
typescript: {
...typescriptParsers.typescript,
preprocess,
},
babel: {
...babelParsers.babel,
preprocess,
},
},
};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@goauthentik/prettier-config",
"version": "2.0.1",
"version": "3.0.0",
"description": "authentik's Prettier config",
"license": "MIT",
"scripts": {
@ -10,19 +10,19 @@
},
"type": "module",
"exports": "./index.js",
"dependencies": {
"format-imports": "^4.0.7"
},
"devDependencies": {
"@goauthentik/tsconfig": "^1.0.1",
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-packagejson": "^2.5.15",
"@types/node": "^24.0.4",
"prettier": "^3.6.1",
"prettier-plugin-packagejson": "^2.5.16",
"typescript": "^5.8.3"
},
"peerDependencies": {
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
"prettier": "^3.5.3",
"prettier-plugin-organize-imports": "^4.1.0",
"prettier-plugin-packagejson": "^2.5.15"
"prettier": "^3.6.1",
"prettier-plugin-packagejson": "^2.5.16"
},
"engines": {
"node": ">=22"