@evertondgn/solid-tooling 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +300 -16
- package/dist/has-match-BITlj0EE.mjs +9 -0
- package/dist/knip.d.mts +12 -0
- package/dist/knip.mjs +92 -0
- package/dist/lint-UTfyg7AR.mjs +983 -0
- package/dist/lint.mjs +1 -983
- package/dist/playwright-teardown.mjs +1 -1
- package/dist/playwright.mjs +3 -3
- package/dist/stylelint.d.mts +8 -0
- package/dist/stylelint.mjs +180 -0
- package/dist/vite.d.mts +40 -0
- package/dist/vite.mjs +341 -0
- package/dist/vitest.mjs +1 -1
- package/package.json +35 -5
package/dist/playwright.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { env, loadEnvFile } from "node:process";
|
|
3
2
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import {
|
|
3
|
+
import { env, loadEnvFile } from "node:process";
|
|
5
4
|
import { loadEnv } from "vite-plus";
|
|
5
|
+
import { defineConfig as defineConfig$1, devices } from "@playwright/test";
|
|
6
6
|
// src/playwright/index.ts
|
|
7
7
|
const STARTUP_TIMEOUT = 12e4;
|
|
8
8
|
const SECONDARY_PORT_OFFSET = 2;
|
|
@@ -121,7 +121,7 @@ function definePlaywrightConfig({ root, testDir = "src/tests/pages", fixtureServ
|
|
|
121
121
|
env.SERVER_LOG_SECONDARY = path.join(root, SECONDARY_LOG);
|
|
122
122
|
}
|
|
123
123
|
const reportFolder = mode.isProduction ? "production" : "e2e";
|
|
124
|
-
return defineConfig({
|
|
124
|
+
return defineConfig$1({
|
|
125
125
|
testDir: path.join(root, testDir),
|
|
126
126
|
testMatch: mode.isProduction ? "**/*.production.e2e.test.ts" : "**/*.e2e.test.ts",
|
|
127
127
|
outputDir: path.join(root, mode.isProduction ? "test-results/e2e-production" : "test-results/e2e"),
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Config } from "stylelint";
|
|
2
|
+
type CssCheck = {
|
|
3
|
+
report: string;
|
|
4
|
+
hasErrors: boolean;
|
|
5
|
+
};
|
|
6
|
+
export declare function defineStylelintConfig(appRoot: string): Promise<Config>;
|
|
7
|
+
export declare function checkCss(appRoot: string): Promise<CssCheck>;
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { cssFilenameError } from "./css-filename.mjs";
|
|
2
|
+
import { t as hasMatch } from "./has-match-BITlj0EE.mjs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readdir } from "node:fs/promises";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import stylelint from "stylelint";
|
|
7
|
+
// src/stylelint/index.ts
|
|
8
|
+
const VAR = String.raw`var\(\s*--[a-z0-9-]+\s*\)`;
|
|
9
|
+
const TOKEN = String.raw`/^${VAR}(?:\s*[,/]\s*${VAR}|\s+${VAR})*$/`;
|
|
10
|
+
const LINE_HEIGHT = String.raw`(?:\d*\.?\d+(?:%|[a-z]+)?|normal)`;
|
|
11
|
+
const FONT_TOKEN = String.raw`/^${VAR}(?:\s+${VAR})*(?:\s*\/\s*(?:${LINE_HEIGHT}|${VAR})(?:\s+${VAR})*)?$/`;
|
|
12
|
+
const TOKEN_KEYWORDS = "/^(?:transparent|currentcolor|inherit|initial|unset|revert|revert-layer|none|auto)$/i";
|
|
13
|
+
const TOKEN_FAMILIES = [
|
|
14
|
+
"color",
|
|
15
|
+
"gradient",
|
|
16
|
+
"radius",
|
|
17
|
+
"shadow",
|
|
18
|
+
"ring",
|
|
19
|
+
"font-size",
|
|
20
|
+
"font-weight",
|
|
21
|
+
"z-index"
|
|
22
|
+
];
|
|
23
|
+
const REFERENCE_FILES = ["src/theme/tokens/**/*.css", "src/theme/class/animation.css"];
|
|
24
|
+
const SYSTEM_COLORS = `
|
|
25
|
+
AccentColor AccentColorText ActiveText ButtonBorder ButtonFace ButtonText
|
|
26
|
+
Canvas CanvasText Field FieldText GrayText Highlight HighlightText LinkText
|
|
27
|
+
Mark MarkText SelectedItem SelectedItemText VisitedText
|
|
28
|
+
ActiveBorder ActiveCaption AppWorkspace Background ButtonHighlight
|
|
29
|
+
ButtonShadow CaptionText InactiveBorder InactiveCaption InactiveCaptionText
|
|
30
|
+
InfoBackground InfoText Menu MenuText Scrollbar ThreeDDarkShadow ThreeDFace
|
|
31
|
+
ThreeDHighlight ThreeDLightShadow ThreeDShadow Window WindowFrame WindowText
|
|
32
|
+
-webkit-activelink -webkit-focus-ring-color -webkit-link -webkit-text
|
|
33
|
+
`.trim().split(/\s+/u);
|
|
34
|
+
const SYSTEM_COLOR = String.raw`/(?<![\w#./-])(?:${SYSTEM_COLORS.join("|")})(?![\w.-])/i`;
|
|
35
|
+
const NAME_PROPERTIES = String.raw`animation(?:-name)?|transition(?:-property)?|will-change|grid(?:-[a-z]+)*|container(?:-name)?|counter-(?:increment|reset|set)|view-transition-(?:class|name)|font-family|content|quotes|list-style(?:-type)?|page`;
|
|
36
|
+
const CSS_FILES = "src/**/*.css";
|
|
37
|
+
function property(names) {
|
|
38
|
+
return String.raw`/^(?!--)(?:-[a-z]+-)?(?:${names})$/i`;
|
|
39
|
+
}
|
|
40
|
+
const TOKEN_PROPERTIES = [
|
|
41
|
+
[property("(?:[a-z]+-)*color|fill|stroke"), ["/^--color-/"]],
|
|
42
|
+
[property("(?:[a-z]+-)*radius"), ["/^--radius-/"]],
|
|
43
|
+
[property("background"), ["/^--(?:color|gradient)-/"]],
|
|
44
|
+
[property("background-image"), ["/^--gradient-/"]],
|
|
45
|
+
[property("box-shadow"), ["/^--(?:shadow|ring)-/"]],
|
|
46
|
+
[property("text-shadow"), []],
|
|
47
|
+
[
|
|
48
|
+
property("font"),
|
|
49
|
+
["/^--font-/"],
|
|
50
|
+
FONT_TOKEN
|
|
51
|
+
],
|
|
52
|
+
[property("font-size"), ["/^--font-size-/"]],
|
|
53
|
+
[property("font-weight"), ["/^--font-weight-/"]],
|
|
54
|
+
[property("z-index"), ["/^--z-index-/"]],
|
|
55
|
+
...TOKEN_FAMILIES.map((family) => [`/^--${family}-/`, [`/^--${family}-/`]]),
|
|
56
|
+
[
|
|
57
|
+
"/^--font-(?!size-|weight-)/",
|
|
58
|
+
["/^--font-/"],
|
|
59
|
+
FONT_TOKEN
|
|
60
|
+
]
|
|
61
|
+
];
|
|
62
|
+
async function referenceFiles(root) {
|
|
63
|
+
return (await Promise.all(REFERENCE_FILES.map(async (pattern) => await hasMatch({
|
|
64
|
+
root,
|
|
65
|
+
pattern
|
|
66
|
+
}) ? [path.join(root, pattern)] : []))).flat();
|
|
67
|
+
}
|
|
68
|
+
async function filenameDiagnostics(root) {
|
|
69
|
+
return (await readdir(path.join(root, "src"), {
|
|
70
|
+
recursive: true,
|
|
71
|
+
withFileTypes: true
|
|
72
|
+
})).flatMap((entry) => {
|
|
73
|
+
if (!entry.isFile()) return [];
|
|
74
|
+
const absolute = path.join(entry.parentPath, entry.name);
|
|
75
|
+
const file = path.relative(root, absolute).split(path.sep).join("/");
|
|
76
|
+
if (!file.endsWith(".css")) return [];
|
|
77
|
+
const message = cssFilenameError(file);
|
|
78
|
+
return message ? [{
|
|
79
|
+
file,
|
|
80
|
+
message
|
|
81
|
+
}] : [];
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
async function defineStylelintConfig(appRoot) {
|
|
85
|
+
const root = path.resolve(appRoot);
|
|
86
|
+
return {
|
|
87
|
+
referenceFiles: await referenceFiles(root),
|
|
88
|
+
reportDescriptionlessDisables: true,
|
|
89
|
+
plugins: [fileURLToPath(import.meta.resolve("stylelint-use-nesting"))],
|
|
90
|
+
rules: {
|
|
91
|
+
"property-no-unknown": true,
|
|
92
|
+
"declaration-property-value-no-unknown": true,
|
|
93
|
+
"value-no-invalid": true,
|
|
94
|
+
"unit-no-unknown": true,
|
|
95
|
+
"color-no-invalid-hex": true,
|
|
96
|
+
"color-no-hex": true,
|
|
97
|
+
"color-named": "never",
|
|
98
|
+
"declaration-block-no-duplicate-properties": [true, { ignore: ["consecutive-duplicates-with-different-syntaxes"] }],
|
|
99
|
+
"declaration-block-no-shorthand-property-overrides": true,
|
|
100
|
+
"selector-pseudo-class-no-unknown": true,
|
|
101
|
+
"selector-pseudo-element-no-unknown": true,
|
|
102
|
+
"selector-type-no-unknown": true,
|
|
103
|
+
"at-rule-no-unknown": true,
|
|
104
|
+
"no-unknown-animations": true,
|
|
105
|
+
"no-unknown-custom-properties": true,
|
|
106
|
+
"custom-property-no-missing-var-function": true,
|
|
107
|
+
"custom-property-pattern": "^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$",
|
|
108
|
+
"selector-no-invalid": true,
|
|
109
|
+
"selector-no-deprecated": true,
|
|
110
|
+
"selector-no-unmatchable": true,
|
|
111
|
+
"at-charset-rule-no-invalid": true,
|
|
112
|
+
"media-query-no-invalid": true,
|
|
113
|
+
"media-feature-name-no-unknown": true,
|
|
114
|
+
"media-feature-name-value-no-unknown": true,
|
|
115
|
+
"function-calc-no-unspaced-operator": true,
|
|
116
|
+
"no-invalid-position-at-import-rule": true,
|
|
117
|
+
"no-duplicate-selectors": true,
|
|
118
|
+
"keyframe-block-no-duplicate-selectors": true,
|
|
119
|
+
"function-disallowed-list": [
|
|
120
|
+
"rgb",
|
|
121
|
+
"rgba",
|
|
122
|
+
"hsl",
|
|
123
|
+
"hsla",
|
|
124
|
+
"hwb",
|
|
125
|
+
"lab",
|
|
126
|
+
"lch",
|
|
127
|
+
"oklab",
|
|
128
|
+
"oklch",
|
|
129
|
+
"color",
|
|
130
|
+
"color-mix",
|
|
131
|
+
"light-dark",
|
|
132
|
+
"contrast-color",
|
|
133
|
+
"device-cmyk"
|
|
134
|
+
],
|
|
135
|
+
"value-type-custom-property-required-list": [["color"], { ignoreValues: [TOKEN_KEYWORDS] }],
|
|
136
|
+
"declaration-property-value-allowed-list": [Object.fromEntries(TOKEN_PROPERTIES.map(([name, , value = TOKEN]) => [name, [value, TOKEN_KEYWORDS]])), { message: "Use only var() tokens in this property; an exception needs a stylelint-disable comment with the reason." }],
|
|
137
|
+
"declaration-property-custom-property-allowed-list": [Object.fromEntries(TOKEN_PROPERTIES.map(([name, families]) => [name, families])), { message: "The property \"%s\" does not accept the token \"%s\"." }],
|
|
138
|
+
"declaration-property-value-disallowed-list": [{ [String.raw`/^(?!(?:-[a-z]+-)?(?:${NAME_PROPERTIES})$)/i`]: [SYSTEM_COLOR] }, { message: "System colors belong in src/theme/." }],
|
|
139
|
+
"selector-class-pattern": ["^[a-z][a-z0-9]*(?:_[a-z0-9]+)*$", { message: "Use snake_case for CSS classes, as in variant_default." }],
|
|
140
|
+
"max-nesting-depth": 2,
|
|
141
|
+
"nesting-selector-no-missing-scoping-root": true,
|
|
142
|
+
"csstools/use-nesting": "always"
|
|
143
|
+
},
|
|
144
|
+
overrides: [{
|
|
145
|
+
files: [path.join(root, "src/theme/**/*.css")],
|
|
146
|
+
rules: {
|
|
147
|
+
"function-disallowed-list": [
|
|
148
|
+
"rgb",
|
|
149
|
+
"rgba",
|
|
150
|
+
"hsl",
|
|
151
|
+
"hsla",
|
|
152
|
+
"hwb",
|
|
153
|
+
"lab",
|
|
154
|
+
"lch",
|
|
155
|
+
"color"
|
|
156
|
+
],
|
|
157
|
+
"value-type-custom-property-required-list": null,
|
|
158
|
+
"declaration-property-value-allowed-list": null,
|
|
159
|
+
"declaration-property-custom-property-allowed-list": null,
|
|
160
|
+
"declaration-property-value-disallowed-list": null
|
|
161
|
+
}
|
|
162
|
+
}]
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
async function checkCss(appRoot) {
|
|
166
|
+
const root = path.resolve(appRoot);
|
|
167
|
+
const config = await defineStylelintConfig(root);
|
|
168
|
+
const [filenames, result] = await Promise.all([filenameDiagnostics(root), stylelint.lint({
|
|
169
|
+
cwd: root,
|
|
170
|
+
files: [CSS_FILES],
|
|
171
|
+
config,
|
|
172
|
+
formatter: "string"
|
|
173
|
+
})]);
|
|
174
|
+
const filenameReport = filenames.map(({ file, message }) => `${file}:1 error project/css-filename: ${message}\n`).join("");
|
|
175
|
+
return {
|
|
176
|
+
report: result.report + filenameReport,
|
|
177
|
+
hasErrors: result.errored || filenames.length > 0
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
export { checkCss, defineStylelintConfig };
|
package/dist/vite.d.mts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { PluginOption, UserConfig, ViteUserConfigFnObject } from "vite-plus";
|
|
2
|
+
import { NitroConfig, NitroModuleInput, PublicAssetDir } from "nitro/types";
|
|
3
|
+
type StaticSecurityHeaders = Record<'strict-transport-security' | 'x-content-type-options' | 'cross-origin-resource-policy', string>;
|
|
4
|
+
type E2eOptions = {
|
|
5
|
+
middleware?: string;
|
|
6
|
+
routes?: string;
|
|
7
|
+
};
|
|
8
|
+
type WorkspaceOptions = {
|
|
9
|
+
dependsOn: string[];
|
|
10
|
+
inputs: string[];
|
|
11
|
+
};
|
|
12
|
+
type StaticAssetDir = PublicAssetDir & {
|
|
13
|
+
baseURL: string;
|
|
14
|
+
};
|
|
15
|
+
type RouteRule = NonNullable<NitroConfig['routeRules']>[string];
|
|
16
|
+
type RunTask = NonNullable<NonNullable<UserConfig['run']>['tasks']>[string];
|
|
17
|
+
type ExtensionContext = {
|
|
18
|
+
target: 'app' | 'test';
|
|
19
|
+
mode: string;
|
|
20
|
+
};
|
|
21
|
+
type SolidAppExtension = {
|
|
22
|
+
plugins?: PluginOption[];
|
|
23
|
+
nitroModules?: NitroModuleInput[];
|
|
24
|
+
};
|
|
25
|
+
type SolidAppOptions = {
|
|
26
|
+
root: string;
|
|
27
|
+
middleware?: string;
|
|
28
|
+
serverSetup?: string;
|
|
29
|
+
e2e?: E2eOptions;
|
|
30
|
+
icons?: Record<string, string>;
|
|
31
|
+
securityHeaders: StaticSecurityHeaders;
|
|
32
|
+
publicAssets?: StaticAssetDir[];
|
|
33
|
+
staticPaths?: string[];
|
|
34
|
+
routeRules?: Record<string, RouteRule>;
|
|
35
|
+
extend?: (context: ExtensionContext) => SolidAppExtension | Promise<SolidAppExtension>;
|
|
36
|
+
workspace?: WorkspaceOptions;
|
|
37
|
+
tasks?: Record<string, RunTask>;
|
|
38
|
+
};
|
|
39
|
+
export declare function defineSolidApp(options: SolidAppOptions): ViteUserConfigFnObject;
|
|
40
|
+
export type { SolidAppOptions };
|
package/dist/vite.mjs
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { fmt } from "./fmt.mjs";
|
|
2
|
+
import { t as lint } from "./lint-UTfyg7AR.mjs";
|
|
3
|
+
import { solidTest } from "./vitest.mjs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { readFile } from "node:fs/promises";
|
|
6
|
+
import { env, loadEnvFile } from "node:process";
|
|
7
|
+
import { defineConfig, lazyPlugins, loadEnv } from "vite-plus";
|
|
8
|
+
// src/vite/plugins.ts
|
|
9
|
+
const ROUTE_TYPES = "src/@types/routes.d.ts";
|
|
10
|
+
const SEO_FILE_PATHS = [
|
|
11
|
+
"/llms.txt",
|
|
12
|
+
"/llms-full.txt",
|
|
13
|
+
"/sitemap.xml",
|
|
14
|
+
"/sitemaps/pages/**",
|
|
15
|
+
"/_markdown/static.json"
|
|
16
|
+
];
|
|
17
|
+
async function loadPluginModules() {
|
|
18
|
+
const [solid, routing, icons, loaders] = await Promise.all([
|
|
19
|
+
import("@solidjs/vite-plugin"),
|
|
20
|
+
import("filesystem-routing/vite"),
|
|
21
|
+
import("unplugin-icons/vite"),
|
|
22
|
+
import("unplugin-icons/loaders")
|
|
23
|
+
]);
|
|
24
|
+
return {
|
|
25
|
+
solid: solid.default,
|
|
26
|
+
fileRoutes: routing.fileRoutes,
|
|
27
|
+
Icons: icons.default,
|
|
28
|
+
FileSystemIconLoader: loaders.FileSystemIconLoader
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function readExtension({ options, target, mode }) {
|
|
32
|
+
return await options.extend?.({
|
|
33
|
+
target,
|
|
34
|
+
mode
|
|
35
|
+
}) ?? {};
|
|
36
|
+
}
|
|
37
|
+
async function readLocales(root) {
|
|
38
|
+
let settings;
|
|
39
|
+
try {
|
|
40
|
+
settings = JSON.parse(await readFile(path.join(root, "project.inlang/settings.json"), "utf8"));
|
|
41
|
+
} catch (error) {
|
|
42
|
+
throw new Error("defineSolidApp: cannot read the locales from project.inlang/settings.json.", { cause: error });
|
|
43
|
+
}
|
|
44
|
+
const locales = settings !== null && typeof settings === "object" && "locales" in settings ? settings.locales : void 0;
|
|
45
|
+
if (!Array.isArray(locales) || !locales.every((locale) => typeof locale === "string")) throw new Error("defineSolidApp: project.inlang/settings.json must list its locales as strings.");
|
|
46
|
+
return locales;
|
|
47
|
+
}
|
|
48
|
+
function isUnderLocale({ staticPath, locales }) {
|
|
49
|
+
const [firstSegment] = staticPath.split("/").slice(1);
|
|
50
|
+
return locales.includes(firstSegment ?? "");
|
|
51
|
+
}
|
|
52
|
+
function staticFilePaths({ options, locales }) {
|
|
53
|
+
const appPaths = [...(options.publicAssets ?? []).map((asset) => `${asset.baseURL}/**`), ...options.staticPaths ?? []];
|
|
54
|
+
const collision = appPaths.find((staticPath) => isUnderLocale({
|
|
55
|
+
staticPath,
|
|
56
|
+
locales
|
|
57
|
+
}));
|
|
58
|
+
if (collision) throw new Error(`defineSolidApp: the static path ${collision} is inside a locale folder; move it out of /${collision.split("/")[1]}/.`);
|
|
59
|
+
return [
|
|
60
|
+
"/assets/**",
|
|
61
|
+
...appPaths,
|
|
62
|
+
...locales.map((locale) => `/${locale}/**.md`),
|
|
63
|
+
...SEO_FILE_PATHS
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
function iconsPlugin({ modules, options }) {
|
|
67
|
+
return modules.Icons({
|
|
68
|
+
compiler: "solid",
|
|
69
|
+
iconCustomizer(_collection, _icon, props) {
|
|
70
|
+
props["aria-hidden"] = "true";
|
|
71
|
+
},
|
|
72
|
+
customCollections: Object.fromEntries(Object.entries(options.icons ?? {}).map(([name, folder]) => [name, modules.FileSystemIconLoader(path.resolve(options.root, folder))]))
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function staticHeaders({ securityHeaders }) {
|
|
76
|
+
return {
|
|
77
|
+
"strict-transport-security": securityHeaders["strict-transport-security"],
|
|
78
|
+
"x-content-type-options": securityHeaders["x-content-type-options"],
|
|
79
|
+
"cross-origin-resource-policy": securityHeaders["cross-origin-resource-policy"]
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function appPlugins({ options, mode }) {
|
|
83
|
+
return lazyPlugins(async () => {
|
|
84
|
+
const [modules, { nitro }, extension, locales] = await Promise.all([
|
|
85
|
+
loadPluginModules(),
|
|
86
|
+
import("nitro/vite"),
|
|
87
|
+
readExtension({
|
|
88
|
+
options,
|
|
89
|
+
target: "app",
|
|
90
|
+
mode
|
|
91
|
+
}),
|
|
92
|
+
readLocales(options.root)
|
|
93
|
+
]);
|
|
94
|
+
const isE2e = mode === "e2e";
|
|
95
|
+
const middleware = isE2e ? options.e2e?.middleware ?? options.middleware : options.middleware;
|
|
96
|
+
const e2eRoutes = isE2e ? options.e2e?.routes : void 0;
|
|
97
|
+
const headers = staticHeaders(options);
|
|
98
|
+
return [
|
|
99
|
+
...extension.plugins ?? [],
|
|
100
|
+
iconsPlugin({
|
|
101
|
+
modules,
|
|
102
|
+
options
|
|
103
|
+
}),
|
|
104
|
+
modules.solid({
|
|
105
|
+
start: middleware ? { middleware } : {},
|
|
106
|
+
ssr: true,
|
|
107
|
+
serverFunctions: options.serverSetup ? { serverSetup: options.serverSetup } : true
|
|
108
|
+
}),
|
|
109
|
+
modules.fileRoutes(e2eRoutes ? {
|
|
110
|
+
dir: e2eRoutes,
|
|
111
|
+
httpMethods: true
|
|
112
|
+
} : {
|
|
113
|
+
types: ROUTE_TYPES,
|
|
114
|
+
httpMethods: true
|
|
115
|
+
}),
|
|
116
|
+
nitro({
|
|
117
|
+
serverEntry: false,
|
|
118
|
+
preset: "vercel",
|
|
119
|
+
modules: extension.nitroModules ?? [],
|
|
120
|
+
publicAssets: options.publicAssets ?? [],
|
|
121
|
+
routeRules: {
|
|
122
|
+
...Object.fromEntries(staticFilePaths({
|
|
123
|
+
options,
|
|
124
|
+
locales
|
|
125
|
+
}).map((staticPath) => [staticPath, { headers }])),
|
|
126
|
+
...options.routeRules
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
];
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
function testPlugins({ options, mode }) {
|
|
133
|
+
return lazyPlugins(async () => {
|
|
134
|
+
const [modules, extension] = await Promise.all([loadPluginModules(), readExtension({
|
|
135
|
+
options,
|
|
136
|
+
target: "test",
|
|
137
|
+
mode
|
|
138
|
+
})]);
|
|
139
|
+
return [
|
|
140
|
+
...extension.plugins ?? [],
|
|
141
|
+
iconsPlugin({
|
|
142
|
+
modules,
|
|
143
|
+
options
|
|
144
|
+
}),
|
|
145
|
+
modules.solid({ serverFunctions: true }),
|
|
146
|
+
modules.fileRoutes({
|
|
147
|
+
types: ROUTE_TYPES,
|
|
148
|
+
httpMethods: true
|
|
149
|
+
})
|
|
150
|
+
];
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
// src/vite/tasks.ts
|
|
154
|
+
const TOOLING_CI_TEST_WORKERS = 3;
|
|
155
|
+
function fromWorkspace(pattern) {
|
|
156
|
+
return {
|
|
157
|
+
pattern,
|
|
158
|
+
base: "workspace"
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function installInputs({ workspace }) {
|
|
162
|
+
const patterns = [
|
|
163
|
+
"bun.lock",
|
|
164
|
+
"bunfig.toml",
|
|
165
|
+
...workspace?.inputs ?? []
|
|
166
|
+
];
|
|
167
|
+
return workspace ? patterns.map((pattern) => fromWorkspace(pattern)) : patterns;
|
|
168
|
+
}
|
|
169
|
+
function createTasks({ workspace, isCi }) {
|
|
170
|
+
const install = installInputs({ workspace });
|
|
171
|
+
const lockfile = workspace ? fromWorkspace("bun.lock") : "bun.lock";
|
|
172
|
+
const dependsOn = workspace ? { dependsOn: workspace.dependsOn } : {};
|
|
173
|
+
const projectCheckInputs = [
|
|
174
|
+
{ auto: true },
|
|
175
|
+
"src/**",
|
|
176
|
+
"paraglide/**",
|
|
177
|
+
"tooling/**",
|
|
178
|
+
"*.ts",
|
|
179
|
+
"tsconfig*.json",
|
|
180
|
+
"package.json",
|
|
181
|
+
"patches/**",
|
|
182
|
+
...install
|
|
183
|
+
];
|
|
184
|
+
const testConcurrency = isCi ? ` --test-concurrency=${TOOLING_CI_TEST_WORKERS}` : "";
|
|
185
|
+
return {
|
|
186
|
+
"i18n-generate": {
|
|
187
|
+
command: "bun tooling/i18n/generate.ts",
|
|
188
|
+
cache: {
|
|
189
|
+
input: [
|
|
190
|
+
"src/**/i18n/*.json",
|
|
191
|
+
"tooling/i18n/**",
|
|
192
|
+
"project.inlang/settings.json",
|
|
193
|
+
"project.inlang/paraglide.config.ts",
|
|
194
|
+
"package.json",
|
|
195
|
+
lockfile
|
|
196
|
+
],
|
|
197
|
+
output: ["paraglide/**", ".paraglide/messages/**"]
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
"lint-css": {
|
|
201
|
+
command: "bun tooling/css/check.ts",
|
|
202
|
+
...dependsOn,
|
|
203
|
+
cache: {
|
|
204
|
+
env: ["NODE_ENV"],
|
|
205
|
+
input: [
|
|
206
|
+
{ auto: true },
|
|
207
|
+
"src/**/*.css",
|
|
208
|
+
"tooling/css/**",
|
|
209
|
+
"package.json",
|
|
210
|
+
...install
|
|
211
|
+
]
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
"dead-code-project": {
|
|
215
|
+
command: "knip-bun --config tooling/knip.ts && knip-bun --config tooling/knip.ts --strict",
|
|
216
|
+
...dependsOn,
|
|
217
|
+
cache: {
|
|
218
|
+
env: ["NODE_ENV"],
|
|
219
|
+
input: [
|
|
220
|
+
{ auto: true },
|
|
221
|
+
"src/**",
|
|
222
|
+
"paraglide/**",
|
|
223
|
+
"tooling/**",
|
|
224
|
+
"*.ts",
|
|
225
|
+
"tsconfig*.json",
|
|
226
|
+
"package.json",
|
|
227
|
+
...install
|
|
228
|
+
],
|
|
229
|
+
output: []
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"lint-project": {
|
|
233
|
+
command: "vp lint",
|
|
234
|
+
dependsOn: ["lint-css"],
|
|
235
|
+
cache: {
|
|
236
|
+
env: ["NODE_ENV"],
|
|
237
|
+
input: projectCheckInputs
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"check-project": {
|
|
241
|
+
command: "vp fmt --check && vp lint",
|
|
242
|
+
dependsOn: ["lint-css"],
|
|
243
|
+
cache: {
|
|
244
|
+
env: ["NODE_ENV"],
|
|
245
|
+
input: projectCheckInputs
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"typecheck-node": {
|
|
249
|
+
command: "tsc --project tsconfig.node.json",
|
|
250
|
+
...dependsOn,
|
|
251
|
+
cache: {
|
|
252
|
+
input: [
|
|
253
|
+
"tsconfig.json",
|
|
254
|
+
"tsconfig.node.json",
|
|
255
|
+
"vite.config.ts",
|
|
256
|
+
"playwright.config.ts",
|
|
257
|
+
"tooling/**/*.ts",
|
|
258
|
+
"src/**/*.ts",
|
|
259
|
+
"src/**/*.tsx",
|
|
260
|
+
"src/**/*.json",
|
|
261
|
+
"project.inlang/paraglide.config.ts",
|
|
262
|
+
"project.inlang/settings.json",
|
|
263
|
+
"package.json",
|
|
264
|
+
"patches/**",
|
|
265
|
+
...install
|
|
266
|
+
],
|
|
267
|
+
output: []
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
"test-tooling": {
|
|
271
|
+
command: `node --test${testConcurrency} --test-timeout=60000 'tooling/__tests__/*.test.ts' 'tooling/!(release)/**/__tests__/*.test.ts'`,
|
|
272
|
+
cache: false
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
// src/vite/index.ts
|
|
277
|
+
function isPathPrefix(baseURL) {
|
|
278
|
+
return typeof baseURL === "string" && baseURL.startsWith("/") && baseURL.length > 1 && !baseURL.endsWith("/");
|
|
279
|
+
}
|
|
280
|
+
function validateOptions(options) {
|
|
281
|
+
const asset = (options.publicAssets ?? []).find(({ baseURL }) => !isPathPrefix(baseURL));
|
|
282
|
+
if (asset) throw new Error(`defineSolidApp: the publicAssets entry for ${asset.dir} needs a baseURL such as /images, without a trailing slash.`);
|
|
283
|
+
const staticPath = (options.staticPaths ?? []).find((pattern) => !pattern.startsWith("/"));
|
|
284
|
+
if (staticPath !== void 0) throw new Error(`defineSolidApp: the static path ${staticPath} must start with a slash.`);
|
|
285
|
+
}
|
|
286
|
+
function loadTestEnvFile(root) {
|
|
287
|
+
try {
|
|
288
|
+
loadEnvFile(path.join(root, ".env.test"));
|
|
289
|
+
} catch (error) {
|
|
290
|
+
if (!(error instanceof Error && "code" in error && error.code === "ENOENT")) throw error;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function defineSolidApp(options) {
|
|
294
|
+
validateOptions(options);
|
|
295
|
+
const { root } = options;
|
|
296
|
+
return defineConfig(({ mode }) => {
|
|
297
|
+
const localEnv = loadEnv(mode, root, ["HOST", "PORT"]);
|
|
298
|
+
const server = {
|
|
299
|
+
host: localEnv.HOST,
|
|
300
|
+
port: localEnv.PORT ? Number(localEnv.PORT) : void 0
|
|
301
|
+
};
|
|
302
|
+
if (mode === "test") loadTestEnvFile(root);
|
|
303
|
+
return {
|
|
304
|
+
run: { tasks: {
|
|
305
|
+
...createTasks({
|
|
306
|
+
workspace: options.workspace,
|
|
307
|
+
isCi: Boolean(env.CI)
|
|
308
|
+
}),
|
|
309
|
+
...options.tasks
|
|
310
|
+
} },
|
|
311
|
+
build: {
|
|
312
|
+
manifest: mode === "e2e",
|
|
313
|
+
rolldownOptions: { output: { comments: false } }
|
|
314
|
+
},
|
|
315
|
+
css: {
|
|
316
|
+
transformer: "lightningcss",
|
|
317
|
+
lightningcss: { cssModules: { pattern: "[content-hash]_[local]" } }
|
|
318
|
+
},
|
|
319
|
+
resolve: { tsconfigPaths: true },
|
|
320
|
+
server: {
|
|
321
|
+
...server,
|
|
322
|
+
forwardConsole: true
|
|
323
|
+
},
|
|
324
|
+
preview: server,
|
|
325
|
+
plugins: mode === "test" ? [] : appPlugins({
|
|
326
|
+
options,
|
|
327
|
+
mode
|
|
328
|
+
}),
|
|
329
|
+
fmt,
|
|
330
|
+
lint,
|
|
331
|
+
test: solidTest({
|
|
332
|
+
root,
|
|
333
|
+
plugins: () => testPlugins({
|
|
334
|
+
options,
|
|
335
|
+
mode
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
};
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
export { defineSolidApp };
|
package/dist/vitest.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evertondgn/solid-tooling",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Lint, formatter, TypeScript and
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Lint, formatter, TypeScript, test and Vite app presets for SolidJS applications built with Vite+.",
|
|
5
5
|
"author": "Éverton Toffanetto",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -27,11 +27,14 @@
|
|
|
27
27
|
"./backend-plugin": "./dist/backend-plugin.mjs",
|
|
28
28
|
"./css-filename": "./dist/css-filename.mjs",
|
|
29
29
|
"./fmt": "./dist/fmt.mjs",
|
|
30
|
+
"./knip": "./dist/knip.mjs",
|
|
30
31
|
"./lint": "./dist/lint.mjs",
|
|
31
32
|
"./playwright": "./dist/playwright.mjs",
|
|
32
33
|
"./playwright-teardown": "./dist/playwright-teardown.mjs",
|
|
33
34
|
"./project-plugin": "./dist/project-plugin.mjs",
|
|
34
35
|
"./solid-plugin": "./dist/solid-plugin.mjs",
|
|
36
|
+
"./stylelint": "./dist/stylelint.mjs",
|
|
37
|
+
"./vite": "./dist/vite.mjs",
|
|
35
38
|
"./vitest": "./dist/vitest.mjs",
|
|
36
39
|
"./vitest-setup/browser": "./dist/vitest-setup/browser.mjs",
|
|
37
40
|
"./package.json": "./package.json",
|
|
@@ -48,12 +51,19 @@
|
|
|
48
51
|
"test:tarball": "vp run test-tarball"
|
|
49
52
|
},
|
|
50
53
|
"dependencies": {
|
|
51
|
-
"eslint-plugin-solid": "0.19.0"
|
|
54
|
+
"eslint-plugin-solid": "0.19.0",
|
|
55
|
+
"stylelint": "18.0.0",
|
|
56
|
+
"stylelint-use-nesting": "6.0.2"
|
|
52
57
|
},
|
|
53
58
|
"peerDependencies": {
|
|
54
59
|
"@inlang/paraglide-js": "3.2.2",
|
|
55
60
|
"vite-plus": "1.6.0",
|
|
56
|
-
"@playwright/test": "1.65.0"
|
|
61
|
+
"@playwright/test": "1.65.0",
|
|
62
|
+
"@solidjs/vite-plugin": "3.0.0-next.57",
|
|
63
|
+
"filesystem-routing": "0.5.0",
|
|
64
|
+
"knip": "6.45.1",
|
|
65
|
+
"nitro": "3.0.261103-rc",
|
|
66
|
+
"unplugin-icons": "24.0.0"
|
|
57
67
|
},
|
|
58
68
|
"devDependencies": {
|
|
59
69
|
"@inlang/paraglide-js": "3.2.2",
|
|
@@ -61,11 +71,31 @@
|
|
|
61
71
|
"typescript": "7.0.2",
|
|
62
72
|
"valibot": "1.5.0",
|
|
63
73
|
"vite-plus": "1.6.0",
|
|
64
|
-
"@playwright/test": "1.65.0"
|
|
74
|
+
"@playwright/test": "1.65.0",
|
|
75
|
+
"@solidjs/vite-plugin": "3.0.0-next.57",
|
|
76
|
+
"filesystem-routing": "0.5.0",
|
|
77
|
+
"knip": "6.45.1",
|
|
78
|
+
"nitro": "3.0.261103-rc",
|
|
79
|
+
"unplugin-icons": "24.0.0"
|
|
65
80
|
},
|
|
66
81
|
"peerDependenciesMeta": {
|
|
67
82
|
"@playwright/test": {
|
|
68
83
|
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"@solidjs/vite-plugin": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"filesystem-routing": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"knip": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"nitro": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
97
|
+
"unplugin-icons": {
|
|
98
|
+
"optional": true
|
|
69
99
|
}
|
|
70
100
|
}
|
|
71
101
|
}
|