Skip to content

Commit 55ddc6f

Browse files
committed
feat(rollup): entry
1 parent af5e1a4 commit 55ddc6f

File tree

4 files changed

+237
-18
lines changed

4 files changed

+237
-18
lines changed

jest.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ module.exports = {
66
babelConfig: true,
77
},
88
},
9-
modulePathIgnorePatterns: ["dist"],
9+
modulePathIgnorePatterns: ["dist", "jest-ignore"],
1010
};

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
"@semantic-release/changelog": "^5.0.1",
4545
"@semantic-release/exec": "^5.0.0",
4646
"@semantic-release/git": "^9.0.0",
47-
"@types/glob": "^7.1.4",
4847
"@types/jest": "^26.0.24",
4948
"@types/rimraf": "^3.0.1",
5049
"@typescript-eslint/eslint-plugin": "^4.28.3",
@@ -72,9 +71,13 @@
7271
},
7372
"dependencies": {
7473
"core-js": "^3.15.2",
74+
"fast-glob": "^3.2.7",
7575
"pascal-case": "^3.1.2",
7676
"tslib": "^2.3.0"
7777
},
78+
"peerDependencies": {
79+
"rollup": "^2.0.0"
80+
},
7881
"files": [
7982
"dist"
8083
],

src/rollup/entry.ts

Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
import * as glob from "fast-glob";
2+
import * as path from "path";
3+
4+
export interface EntryFileInfo {
5+
moduleName: string;
6+
fileRelativePath: string;
7+
index: number;
8+
baseDir: string;
9+
}
10+
11+
export type EntryFileFormatterSync = (
12+
info: EntryFileInfo,
13+
) => readonly [string, string];
14+
15+
export type EntryFileFormatter = (
16+
...args: Parameters<EntryFileFormatterSync>
17+
) =>
18+
| Promise<ReturnType<EntryFileFormatterSync>>
19+
| ReturnType<EntryFileFormatterSync>;
20+
21+
interface MatchFilesOptions {
22+
patterns: string | string[];
23+
baseDir: string;
24+
ignore: string | string[];
25+
}
26+
27+
export interface GetEntryFilesOptionsCommon extends Partial<MatchFilesOptions> {
28+
keepIndexFiles?: boolean;
29+
}
30+
31+
export interface GetEntryFilesOptions extends GetEntryFilesOptionsCommon {
32+
formatter?: EntryFileFormatter;
33+
}
34+
35+
export interface GetEntryFilesOptionsSync extends GetEntryFilesOptionsCommon {
36+
formatter?: EntryFileFormatterSync;
37+
}
38+
39+
function getGlobArgs({
40+
patterns,
41+
baseDir,
42+
ignore,
43+
}: MatchFilesOptions): Parameters<typeof glob> {
44+
return [
45+
patterns,
46+
{
47+
cwd: baseDir,
48+
ignore: typeof ignore === "string" ? [ignore] : ignore,
49+
},
50+
];
51+
}
52+
53+
export const DEFAULT_PATTERNS_EXT = "js,jsx,ts,tsx,json";
54+
export const DEFAULT_PATTERNS = [
55+
`./*.{${DEFAULT_PATTERNS_EXT}}`,
56+
`./*/index.{${DEFAULT_PATTERNS_EXT}}`,
57+
];
58+
59+
export const DEFAULT_IGNORE = [
60+
"**/*.d.ts",
61+
`**/*.{test,spec}.{${DEFAULT_PATTERNS_EXT}}`,
62+
`**/{__test__,__spec__}/**`,
63+
];
64+
65+
function getModuleNameFromFile(info: path.ParsedPath) {
66+
return path.posix.join(info.dir, info.name);
67+
}
68+
69+
function isSubDirIndexFile(info: path.ParsedPath) {
70+
const { name } = info;
71+
return name === "index" || name.startsWith("index.");
72+
}
73+
74+
function getModuleNamesFromFiles(
75+
files: string[],
76+
keepIndexFiles: boolean,
77+
): (readonly [moduleName: string, file: string])[] {
78+
files = files.map((f) => path.posix.normalize(f));
79+
80+
const infoAndFiles = files.map((f) => [path.posix.parse(f), f] as const);
81+
82+
if (keepIndexFiles) {
83+
return infoAndFiles.map(
84+
([info, file]) => [getModuleNameFromFile(info), file] as const,
85+
);
86+
}
87+
88+
const dirStatus = new Map<
89+
string,
90+
{ hasIndex: boolean; hasOtherFiles: boolean }
91+
>();
92+
93+
for (const [info] of infoAndFiles) {
94+
const { dir } = info;
95+
let status = dirStatus.get(dir);
96+
if (!status) {
97+
status = { hasIndex: false, hasOtherFiles: false };
98+
dirStatus.set(dir, status);
99+
}
100+
101+
if (!status.hasIndex && isSubDirIndexFile(info)) {
102+
status.hasIndex = true;
103+
} else {
104+
status.hasOtherFiles = true;
105+
}
106+
}
107+
108+
for (const subDir of dirStatus.keys()) {
109+
for (const [dir, status] of dirStatus) {
110+
if (subDir.startsWith(dir + "/")) {
111+
status.hasOtherFiles = true;
112+
}
113+
}
114+
}
115+
116+
return infoAndFiles.map(([info, file]) => {
117+
const { dir } = info;
118+
const status = dirStatus.get(dir);
119+
if (dir !== "" && status && status.hasIndex && !status.hasOtherFiles) {
120+
// only process the dirs which only has one index file
121+
return [dir, file] as const;
122+
} else {
123+
return [getModuleNameFromFile(info), file] as const;
124+
}
125+
});
126+
}
127+
128+
function validateFormatterReturnValue(
129+
newValue: readonly [string, string],
130+
warnPromise = false,
131+
): readonly [string, string] {
132+
if (
133+
newValue &&
134+
typeof newValue[0] === "string" &&
135+
typeof newValue[1] === "string"
136+
) {
137+
return newValue;
138+
} else {
139+
throw new Error(
140+
`getEntryFilesSync formatter is expected to return a [string, string], but returned ${
141+
warnPromise && newValue instanceof Promise
142+
? "a Promise. Please consider using getEntryFiles"
143+
: String(newValue)
144+
}.`,
145+
);
146+
}
147+
}
148+
149+
function tupleModuleNameFileToInfo(
150+
tuple: readonly [string, string],
151+
index: number,
152+
baseDir: string,
153+
): EntryFileInfo {
154+
return {
155+
moduleName: tuple[0],
156+
fileRelativePath: tuple[1],
157+
index,
158+
baseDir,
159+
};
160+
}
161+
162+
export function getEntryFilesSync({
163+
formatter,
164+
patterns = DEFAULT_PATTERNS,
165+
baseDir = "src",
166+
ignore = DEFAULT_IGNORE,
167+
keepIndexFiles = false,
168+
}: GetEntryFilesOptionsSync = {}): Record<string, string> {
169+
const files = glob.sync(
170+
...getGlobArgs({
171+
patterns,
172+
baseDir,
173+
ignore,
174+
}),
175+
);
176+
177+
let entries = getModuleNamesFromFiles(files, keepIndexFiles);
178+
179+
if (formatter) {
180+
entries = entries
181+
.map((tuple, i) => tupleModuleNameFileToInfo(tuple, i, baseDir))
182+
.map((info) => {
183+
const newValue = formatter(info);
184+
return validateFormatterReturnValue(newValue);
185+
});
186+
}
187+
188+
const entryFiles = Object.fromEntries(entries);
189+
190+
return entryFiles;
191+
}
192+
193+
export async function getEntryFiles({
194+
formatter,
195+
patterns = DEFAULT_PATTERNS,
196+
baseDir = "src",
197+
ignore = DEFAULT_IGNORE,
198+
keepIndexFiles = false,
199+
}: GetEntryFilesOptions = {}): Promise<Record<string, string>> {
200+
const files = await glob(
201+
...getGlobArgs({
202+
patterns,
203+
baseDir,
204+
ignore,
205+
}),
206+
);
207+
208+
let entries = getModuleNamesFromFiles(files, keepIndexFiles);
209+
210+
if (formatter) {
211+
entries = await Promise.all(
212+
entries
213+
.map((tuple, i) => tupleModuleNameFileToInfo(tuple, i, baseDir))
214+
.map(async (info) => {
215+
const newValue = await formatter(info);
216+
return validateFormatterReturnValue(newValue);
217+
}),
218+
);
219+
}
220+
221+
const entryFiles = Object.fromEntries(entries);
222+
223+
return entryFiles;
224+
}

yarn.lock

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,7 +1762,7 @@
17621762
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
17631763
integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
17641764

1765-
"@types/glob@*", "@types/glob@^7.1.4":
1765+
"@types/glob@*":
17661766
version "7.1.4"
17671767
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672"
17681768
integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==
@@ -3632,17 +3632,16 @@ fast-diff@^1.1.2:
36323632
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
36333633
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
36343634

3635-
fast-glob@^3.1.1:
3636-
version "3.2.4"
3637-
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
3638-
integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==
3635+
fast-glob@^3.1.1, fast-glob@^3.2.7:
3636+
version "3.2.7"
3637+
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
3638+
integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
36393639
dependencies:
36403640
"@nodelib/fs.stat" "^2.0.2"
36413641
"@nodelib/fs.walk" "^1.2.3"
3642-
glob-parent "^5.1.0"
3642+
glob-parent "^5.1.2"
36433643
merge2 "^1.3.0"
3644-
micromatch "^4.0.2"
3645-
picomatch "^2.2.1"
3644+
micromatch "^4.0.4"
36463645

36473646
[email protected], fast-json-stable-stringify@^2.0.0:
36483647
version "2.1.0"
@@ -3969,13 +3968,6 @@ git-log-parser@^1.2.0:
39693968
through2 "~2.0.0"
39703969
traverse "~0.6.6"
39713970

3972-
glob-parent@^5.1.0:
3973-
version "5.1.1"
3974-
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
3975-
integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
3976-
dependencies:
3977-
is-glob "^4.0.1"
3978-
39793971
glob-parent@^5.1.2:
39803972
version "5.1.2"
39813973
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@@ -6645,7 +6637,7 @@ performance-now@^2.1.0:
66456637
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
66466638
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
66476639

6648-
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1, picomatch@^2.2.2:
6640+
picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.2:
66496641
version "2.2.2"
66506642
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
66516643
integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==

0 commit comments

Comments
 (0)