@zealakit/css-doctor-next 1.0.0 → 1.1.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/LICENSE +21 -0
- package/dist/index.cjs +120 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +120 -36
- package/dist/index.js.map +1 -1
- package/package.json +24 -2
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Zealamic
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
CHANGED
|
@@ -399,7 +399,10 @@ var CssDoctorWebpackPlugin = class {
|
|
|
399
399
|
pageUsage[page.name] = classes;
|
|
400
400
|
pageUsageCounts[page.name] = classes.length;
|
|
401
401
|
}
|
|
402
|
-
const
|
|
402
|
+
const hasPageClasses = pagesResult.pages.some(
|
|
403
|
+
(page) => page.classes.size > 0
|
|
404
|
+
);
|
|
405
|
+
const pageCoverageApplied = this.pageCoverage.enabled && hasPageClasses;
|
|
403
406
|
const diagnostics = {
|
|
404
407
|
plugin: "css-doctor-next",
|
|
405
408
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -488,7 +491,7 @@ var CssDoctorWebpackPlugin = class {
|
|
|
488
491
|
cssContent: originalCss,
|
|
489
492
|
pageUsage,
|
|
490
493
|
pageCoverage: {
|
|
491
|
-
enabled:
|
|
494
|
+
enabled: pageCoverageApplied,
|
|
492
495
|
minPageRatio: this.pageCoverage.minPageRatio,
|
|
493
496
|
forceCommon: this.pageCoverage.forceCommon
|
|
494
497
|
},
|
|
@@ -748,6 +751,7 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
748
751
|
const pageEntries = [];
|
|
749
752
|
const sharedEntries = [];
|
|
750
753
|
const fallbackEntries = [];
|
|
754
|
+
const loaderFallbackEntries = [];
|
|
751
755
|
for (const entry of entries) {
|
|
752
756
|
const name = entryName(entry);
|
|
753
757
|
if (!name) {
|
|
@@ -764,12 +768,19 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
764
768
|
name: routeNameForEntry(name) ?? name,
|
|
765
769
|
sourceName: name
|
|
766
770
|
});
|
|
771
|
+
} else {
|
|
772
|
+
loaderFallbackEntries.push({
|
|
773
|
+
entry,
|
|
774
|
+
name: routeNameForEntry(name) ?? name,
|
|
775
|
+
sourceName: name
|
|
776
|
+
});
|
|
767
777
|
}
|
|
768
778
|
}
|
|
769
779
|
const selectedPages = pageEntries.length > 0 ? pageEntries : fallbackEntries;
|
|
770
780
|
const direct = directPageUsage ? Object.keys(directPageUsage).length > 0 : false;
|
|
771
781
|
const pages = /* @__PURE__ */ new Map();
|
|
772
782
|
const pagesByCss = /* @__PURE__ */ new Map();
|
|
783
|
+
const projectRoot = compilation.compiler?.context ?? process.cwd();
|
|
773
784
|
if (direct && directPageUsage) {
|
|
774
785
|
for (const [rawName, classes] of Object.entries(directPageUsage)) {
|
|
775
786
|
const name = rawName.trim();
|
|
@@ -783,10 +794,27 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
783
794
|
jsFiles: /* @__PURE__ */ new Set()
|
|
784
795
|
});
|
|
785
796
|
}
|
|
797
|
+
attachEntryAssetsToPages(pages, selectedPages);
|
|
798
|
+
const orphanPages = [...pages.values()].filter(
|
|
799
|
+
(page) => page.jsFiles.size === 0
|
|
800
|
+
);
|
|
801
|
+
if (orphanPages.length > 0) {
|
|
802
|
+
const loaderEntries = selectedPages.length > 0 ? selectedPages : loaderFallbackEntries;
|
|
803
|
+
const fallbackJs = /* @__PURE__ */ new Set();
|
|
804
|
+
for (const { entry } of loaderEntries) {
|
|
805
|
+
for (const jsFile of collectEntryJsFiles(entry)) {
|
|
806
|
+
fallbackJs.add(jsFile);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
for (const page of orphanPages) {
|
|
810
|
+
for (const jsFile of fallbackJs) {
|
|
811
|
+
page.jsFiles.add(jsFile);
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
786
815
|
} else {
|
|
787
816
|
const sourceCache = /* @__PURE__ */ new Map();
|
|
788
817
|
const sharedClasses = /* @__PURE__ */ new Set();
|
|
789
|
-
const projectRoot = process.cwd();
|
|
790
818
|
for (const entry of sharedEntries) {
|
|
791
819
|
for (const className of await collectEntryClasses(
|
|
792
820
|
compilation,
|
|
@@ -839,19 +867,10 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
839
867
|
const targetPages = [...pages.keys()];
|
|
840
868
|
for (const { entry, name } of selectedPages) {
|
|
841
869
|
const cssFiles = collectEntryCssFiles(entry);
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
directPage.cssFiles.add(cssFile);
|
|
847
|
-
}
|
|
848
|
-
}
|
|
849
|
-
} else {
|
|
850
|
-
const page = pages.get(name);
|
|
851
|
-
if (page) {
|
|
852
|
-
for (const cssFile of cssFiles) {
|
|
853
|
-
page.cssFiles.add(cssFile);
|
|
854
|
-
}
|
|
870
|
+
const page = findPageForEntry(pages, name);
|
|
871
|
+
if (page) {
|
|
872
|
+
for (const cssFile of cssFiles) {
|
|
873
|
+
page.cssFiles.add(cssFile);
|
|
855
874
|
}
|
|
856
875
|
}
|
|
857
876
|
}
|
|
@@ -876,18 +895,46 @@ async function collectPages(compilation, directPageUsage) {
|
|
|
876
895
|
pagesByCss
|
|
877
896
|
};
|
|
878
897
|
}
|
|
898
|
+
function attachEntryAssetsToPages(pages, selectedPages) {
|
|
899
|
+
for (const { entry, name } of selectedPages) {
|
|
900
|
+
const page = findPageForEntry(pages, name);
|
|
901
|
+
if (!page) {
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
for (const jsFile of collectEntryJsFiles(entry)) {
|
|
905
|
+
page.jsFiles.add(jsFile);
|
|
906
|
+
}
|
|
907
|
+
for (const cssFile of collectEntryCssFiles(entry)) {
|
|
908
|
+
page.cssFiles.add(cssFile);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function findPageForEntry(pages, entryNameValue) {
|
|
913
|
+
const direct = pages.get(entryNameValue);
|
|
914
|
+
if (direct) {
|
|
915
|
+
return direct;
|
|
916
|
+
}
|
|
917
|
+
const normalized = normalizeSlashes(entryNameValue).replace(/^\/+/, "");
|
|
918
|
+
const bare = normalized.replace(/^\//, "");
|
|
919
|
+
return pages.get(normalized) ?? pages.get(`/${bare}`) ?? pages.get(bare) ?? pages.get(bare.replace(/\//g, "-"));
|
|
920
|
+
}
|
|
879
921
|
async function collectPageSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
880
922
|
const classes = /* @__PURE__ */ new Set();
|
|
881
923
|
const visited = /* @__PURE__ */ new Set();
|
|
882
924
|
const normalized = normalizeSlashes(entryName2);
|
|
925
|
+
const roots = projectSourceRoots(projectRoot);
|
|
883
926
|
const candidates = [];
|
|
884
927
|
if (normalized.startsWith("app/")) {
|
|
885
928
|
const path = normalized.slice(4);
|
|
886
929
|
if (path === "page" || path.endsWith("/page")) {
|
|
887
930
|
const pagePath = path === "page" ? "app/page" : `app/${path}`;
|
|
888
|
-
|
|
931
|
+
for (const root of roots) {
|
|
932
|
+
candidates.push((0, import_node_path2.resolve)(root, pagePath));
|
|
933
|
+
}
|
|
889
934
|
if (path === "_not-found/page") {
|
|
890
|
-
|
|
935
|
+
for (const root of roots) {
|
|
936
|
+
candidates.push((0, import_node_path2.resolve)(root, "app/not-found"));
|
|
937
|
+
}
|
|
891
938
|
}
|
|
892
939
|
const directories = path.split("/").slice(0, -1).filter(Boolean);
|
|
893
940
|
const layoutPaths = ["app"];
|
|
@@ -895,16 +942,24 @@ async function collectPageSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
|
895
942
|
layoutPaths.push(`app/${directories.slice(0, index + 1).join("/")}`);
|
|
896
943
|
}
|
|
897
944
|
for (const layoutPath of layoutPaths) {
|
|
898
|
-
|
|
945
|
+
for (const root of roots) {
|
|
946
|
+
candidates.push((0, import_node_path2.resolve)(root, `${layoutPath}/layout`));
|
|
947
|
+
}
|
|
899
948
|
}
|
|
900
949
|
} else {
|
|
901
|
-
|
|
950
|
+
for (const root of roots) {
|
|
951
|
+
candidates.push((0, import_node_path2.resolve)(root, normalized));
|
|
952
|
+
}
|
|
902
953
|
}
|
|
903
954
|
} else if (normalized.startsWith("pages/")) {
|
|
904
|
-
|
|
905
|
-
|
|
955
|
+
for (const root of roots) {
|
|
956
|
+
candidates.push((0, import_node_path2.resolve)(root, normalized));
|
|
957
|
+
candidates.push((0, import_node_path2.resolve)(root, "pages/_app"));
|
|
958
|
+
}
|
|
906
959
|
} else {
|
|
907
|
-
|
|
960
|
+
for (const root of roots) {
|
|
961
|
+
candidates.push((0, import_node_path2.resolve)(root, normalized));
|
|
962
|
+
}
|
|
908
963
|
}
|
|
909
964
|
for (const candidate of candidates) {
|
|
910
965
|
const file = findSourceFile(candidate);
|
|
@@ -917,13 +972,23 @@ async function collectPageSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
|
917
972
|
async function collectNameSourceClasses(entryName2, projectRoot, sourceCache) {
|
|
918
973
|
const classes = /* @__PURE__ */ new Set();
|
|
919
974
|
const visited = /* @__PURE__ */ new Set();
|
|
920
|
-
const
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
|
|
975
|
+
const relative = normalizeSlashes(entryName2);
|
|
976
|
+
for (const root of projectSourceRoots(projectRoot)) {
|
|
977
|
+
const file = findSourceFile((0, import_node_path2.resolve)(root, relative));
|
|
978
|
+
if (file) {
|
|
979
|
+
await scanSourceFile(file, classes, projectRoot, sourceCache, visited);
|
|
980
|
+
}
|
|
924
981
|
}
|
|
925
982
|
return classes;
|
|
926
983
|
}
|
|
984
|
+
function projectSourceRoots(projectRoot) {
|
|
985
|
+
const roots = [projectRoot];
|
|
986
|
+
const srcRoot = (0, import_node_path2.resolve)(projectRoot, "src");
|
|
987
|
+
if (srcRoot !== projectRoot && (0, import_node_fs2.existsSync)(srcRoot)) {
|
|
988
|
+
roots.push(srcRoot);
|
|
989
|
+
}
|
|
990
|
+
return roots;
|
|
991
|
+
}
|
|
927
992
|
async function scanSourceFile(filePath, classes, projectRoot, sourceCache, visited) {
|
|
928
993
|
const absolutePath = (0, import_node_path2.resolve)(filePath);
|
|
929
994
|
if (visited.has(absolutePath)) {
|
|
@@ -1007,18 +1072,28 @@ function extractImportSpecifiers(source) {
|
|
|
1007
1072
|
return [...specifiers];
|
|
1008
1073
|
}
|
|
1009
1074
|
function resolveImportSpecifier(specifier, fromFile, projectRoot) {
|
|
1010
|
-
let basePath;
|
|
1011
1075
|
if (specifier.startsWith("@/")) {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1076
|
+
const relative = specifier.slice(2);
|
|
1077
|
+
for (const root of projectSourceRoots(projectRoot)) {
|
|
1078
|
+
const basePath = (0, import_node_path2.resolve)(root, relative);
|
|
1079
|
+
if (isStyleFile(basePath)) {
|
|
1080
|
+
return null;
|
|
1081
|
+
}
|
|
1082
|
+
const found = findSourceFile(basePath);
|
|
1083
|
+
if (found) {
|
|
1084
|
+
return found;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1016
1087
|
return null;
|
|
1017
1088
|
}
|
|
1018
|
-
if (
|
|
1019
|
-
|
|
1089
|
+
if (specifier.startsWith("./") || specifier.startsWith("../")) {
|
|
1090
|
+
const basePath = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(fromFile), specifier);
|
|
1091
|
+
if (isStyleFile(basePath)) {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
return findSourceFile(basePath);
|
|
1020
1095
|
}
|
|
1021
|
-
return
|
|
1096
|
+
return null;
|
|
1022
1097
|
}
|
|
1023
1098
|
async function collectEntryClasses(compilation, entry, sourceCache) {
|
|
1024
1099
|
const classes = /* @__PURE__ */ new Set();
|
|
@@ -1187,13 +1262,22 @@ function scanClasses(source, classes) {
|
|
|
1187
1262
|
continue;
|
|
1188
1263
|
}
|
|
1189
1264
|
for (const token of value.split(/\s+/)) {
|
|
1190
|
-
if (
|
|
1265
|
+
if (isClassToken(token)) {
|
|
1191
1266
|
classes.add(token.toLowerCase());
|
|
1192
1267
|
}
|
|
1193
1268
|
}
|
|
1194
1269
|
}
|
|
1195
1270
|
}
|
|
1196
1271
|
}
|
|
1272
|
+
function isClassToken(token) {
|
|
1273
|
+
if (!token || token.length > 256) {
|
|
1274
|
+
return false;
|
|
1275
|
+
}
|
|
1276
|
+
if (/[`${}]/.test(token)) {
|
|
1277
|
+
return false;
|
|
1278
|
+
}
|
|
1279
|
+
return /[A-Za-z_]/.test(token);
|
|
1280
|
+
}
|
|
1197
1281
|
function addCssOwner(pagesByCss, cssFile, page) {
|
|
1198
1282
|
const owners = pagesByCss.get(cssFile) ?? /* @__PURE__ */ new Set();
|
|
1199
1283
|
owners.add(page);
|