@k8slens/package-build 2.2.3 → 3.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/bin/extension-dependencies-check +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +581 -319
- package/dist/src/extension-dependencies-check.d.ts +21 -0
- package/dist/src/extension-dependencies-check.d.ts.map +1 -0
- package/dist/src/package-build.d.ts.map +1 -1
- package/dist/src/stylesheet-plugin.d.ts +33 -0
- package/dist/src/stylesheet-plugin.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +12 -6
- package/src/__fixtures__/package-with-undeclared-dependency/index.js +1 -0
- package/src/__fixtures__/package-with-undeclared-dependency/manifest.json +6 -0
- package/src/__fixtures__/package-without-dependency/index.js +1 -0
- package/src/__fixtures__/package-without-dependency/manifest.json +3 -0
- package/src/__fixtures__/package-without-dependency/some.scss +3 -0
- package/src/__fixtures__/styled-package/_partial.scss +1 -0
- package/src/__fixtures__/styled-package/empty.scss +1 -0
- package/src/__fixtures__/styled-package/fonts/some-font.ttf +1 -0
- package/src/__fixtures__/styled-package/fonts.scss +8 -0
- package/src/__fixtures__/styled-package/global.scss +3 -0
- package/src/__fixtures__/styled-package/importer.scss +5 -0
- package/src/__fixtures__/styled-package/index.js +10 -0
- package/src/__fixtures__/styled-package/manifest.json +7 -0
- package/src/__fixtures__/styled-package/plain.css +3 -0
- package/src/__fixtures__/styled-package/plain.module.css +3 -0
- package/src/__fixtures__/styled-package/some.module.scss +7 -0
- package/src/__fixtures__/styled-package/tilde.scss +7 -0
- package/src/extension-dependencies-check.test.ts +259 -0
- package/src/extension-dependencies-check.ts +158 -0
- package/src/package-build.ts +7 -15
- package/src/stylesheet-plugin.test.ts +161 -0
- package/src/stylesheet-plugin.ts +272 -0
- package/src/glob-import-plugin.js +0 -46
- package/src/package-build.js +0 -193
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@k8slens/package-build",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"lens": {
|
|
5
5
|
"env": "agnostic",
|
|
6
6
|
"layer": "infrastructure",
|
|
@@ -41,7 +41,8 @@
|
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
43
|
"bin": {
|
|
44
|
-
"lens-package-build": "bin/package-build"
|
|
44
|
+
"lens-package-build": "bin/package-build",
|
|
45
|
+
"lens-extension-dependencies-check": "bin/extension-dependencies-check"
|
|
45
46
|
},
|
|
46
47
|
"files": [
|
|
47
48
|
"index.js",
|
|
@@ -50,26 +51,30 @@
|
|
|
50
51
|
"dist"
|
|
51
52
|
],
|
|
52
53
|
"scripts": {
|
|
53
|
-
"build:infrastructure:code": "esbuild --bundle index.ts --outfile=dist/index.js --external:node:* --external:postcss --external:esbuild --external:fast-glob --external:
|
|
54
|
+
"build:infrastructure:code": "esbuild --bundle index.ts --outfile=dist/index.js --external:node:* --external:postcss --external:postcss-modules --external:esbuild --external:fast-glob --external:sass --external:yargs --external:semver --external:tailwindcss --format=cjs",
|
|
54
55
|
"build:infrastructure:types": "tsc --project .",
|
|
55
56
|
"build:infrastructure": "npm run build:infrastructure:code; npm run build:infrastructure:types",
|
|
56
57
|
"lint": "lens-verify-code-style",
|
|
57
58
|
"clean": "exit 0",
|
|
58
|
-
"check-types:tests": "lens-types-build --checkTypesTests"
|
|
59
|
+
"check-types:tests": "lens-types-build --checkTypesTests",
|
|
60
|
+
"test:unit": "jest"
|
|
59
61
|
},
|
|
60
62
|
"dependencies": {
|
|
61
63
|
"esbuild": "^0.25.4",
|
|
62
|
-
"esbuild-sass-plugin": "^3.3.1",
|
|
63
64
|
"fast-glob": "^3.3.3",
|
|
64
65
|
"lodash": "^4.17.21",
|
|
65
66
|
"postcss": "^8.5.18",
|
|
66
67
|
"postcss-modules": "^6.0.1",
|
|
68
|
+
"sass": "^1.89.0",
|
|
69
|
+
"semver": "^7.7.2",
|
|
67
70
|
"tailwindcss": "^3.4.17",
|
|
68
71
|
"yargs": "^17.7.2"
|
|
69
72
|
},
|
|
70
73
|
"devDependencies": {
|
|
71
74
|
"@async-fn/jest": "^1.6.4",
|
|
72
|
-
"@k8slens/typescript": "^
|
|
75
|
+
"@k8slens/typescript": "^8.0.0",
|
|
76
|
+
"@lensapp/jest": "^7.2.0",
|
|
77
|
+
"@types/semver": "^7.7.0"
|
|
73
78
|
},
|
|
74
79
|
"publishConfig": {
|
|
75
80
|
"access": "public",
|
|
@@ -80,6 +85,7 @@
|
|
|
80
85
|
"build:infrastructure": {
|
|
81
86
|
"inputs": [
|
|
82
87
|
"{projectRoot}/bin/package-build",
|
|
88
|
+
"{projectRoot}/bin/extension-dependencies-check",
|
|
83
89
|
"{projectRoot}/index.ts",
|
|
84
90
|
"{projectRoot}/src/**/*.ts"
|
|
85
91
|
],
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "overlayscrollbars/overlayscrollbars.css";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./some.scss";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$partialColor: purple;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$unused: 1;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
not really a font
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * as ofDependency from "overlayscrollbars/overlayscrollbars.css";
|
|
2
|
+
|
|
3
|
+
export * as global from "./global.scss";
|
|
4
|
+
export * as someModule from "./some.module.scss";
|
|
5
|
+
export * as importer from "./importer.scss";
|
|
6
|
+
export * as empty from "./empty.scss";
|
|
7
|
+
export * as plain from "./plain.css";
|
|
8
|
+
export * as plainModule from "./plain.module.css";
|
|
9
|
+
export * as tilde from "./tilde.scss";
|
|
10
|
+
export * as fonts from "./fonts.scss";
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { checkExtensionDependencies, extensionDependenciesCheck } from "./extension-dependencies-check";
|
|
5
|
+
|
|
6
|
+
const originalArgv = process.argv;
|
|
7
|
+
|
|
8
|
+
describe("checking an extension's dependency ranges against the versions Lens serves", () => {
|
|
9
|
+
let directory: string;
|
|
10
|
+
let packageJsonPath: string;
|
|
11
|
+
let versionsFilePath: string;
|
|
12
|
+
let logged: string[];
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
directory = mkdtempSync(path.join(tmpdir(), "extension-dependencies-check-"));
|
|
16
|
+
packageJsonPath = path.join(directory, "package.json");
|
|
17
|
+
versionsFilePath = path.join(directory, "extension-dependency-versions.json");
|
|
18
|
+
logged = [];
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
rmSync(directory, { recursive: true, force: true });
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const check = ({ fix = false } = {}) =>
|
|
26
|
+
checkExtensionDependencies({ packageJsonPath, versionsFilePath, fix, log: (line) => logged.push(line) });
|
|
27
|
+
|
|
28
|
+
const givenPackageJson = (packageJson: object) =>
|
|
29
|
+
writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
30
|
+
|
|
31
|
+
const givenLensServes = (versions: Record<string, string>) =>
|
|
32
|
+
writeFileSync(versionsFilePath, JSON.stringify(versions));
|
|
33
|
+
|
|
34
|
+
describe("given Lens on this machine has written no versions, when checked", () => {
|
|
35
|
+
let exitCode: number;
|
|
36
|
+
|
|
37
|
+
beforeEach(() => {
|
|
38
|
+
givenPackageJson({ dependencies: { "some-package": "^999.0.0" } });
|
|
39
|
+
|
|
40
|
+
exitCode = check();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("passes", () => {
|
|
44
|
+
expect(exitCode).toBe(0);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("says in one line that the check was skipped, naming the file it looked for", () => {
|
|
48
|
+
expect(logged).toEqual([
|
|
49
|
+
`Skipped checking dependency ranges against Lens: no "${versionsFilePath}", which Lens writes when it runs on this machine.`,
|
|
50
|
+
]);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("given ranges that include every version Lens serves, when checked", () => {
|
|
55
|
+
let exitCode: number;
|
|
56
|
+
|
|
57
|
+
beforeEach(() => {
|
|
58
|
+
givenLensServes({ "some-package": "1.2.0", "@some-scope/some-other-package": "2.0.0-beta.1" });
|
|
59
|
+
|
|
60
|
+
givenPackageJson({
|
|
61
|
+
dependencies: { "some-package": "^1.0.0", "some-package-lens-does-not-serve": "^999.0.0" },
|
|
62
|
+
peerDependencies: { "@some-scope/some-other-package": "^2.0.0-beta.0" },
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
exitCode = check();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("passes", () => {
|
|
69
|
+
expect(exitCode).toBe(0);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("says every range includes the version Lens serves", () => {
|
|
73
|
+
expect(logged).toEqual([
|
|
74
|
+
`Every dependency range includes the version Lens serves (read from "${versionsFilePath}").`,
|
|
75
|
+
]);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
describe("given a range in dependencies that excludes the version Lens serves, when checked", () => {
|
|
80
|
+
let exitCode: number;
|
|
81
|
+
|
|
82
|
+
beforeEach(() => {
|
|
83
|
+
givenLensServes({ react: "19.2.0" });
|
|
84
|
+
givenPackageJson({ dependencies: { react: "^19.3.1" } });
|
|
85
|
+
|
|
86
|
+
exitCode = check();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("fails", () => {
|
|
90
|
+
expect(exitCode).toBe(1);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("names the range, the version Lens serves, the range to declare instead and how to fix it", () => {
|
|
94
|
+
expect(logged).toEqual([
|
|
95
|
+
[
|
|
96
|
+
`Lens would refuse to load this extension. These ranges in package.json do not include the version Lens serves (read from "${versionsFilePath}"):`,
|
|
97
|
+
` in dependencies, "react": "^19.3.1" does not include Lens's 19.2.0, declare "^19.2.0"`,
|
|
98
|
+
`Run "npx lens-extension-dependencies-check --fix" to rewrite them, then "npm install".`,
|
|
99
|
+
].join("\n"),
|
|
100
|
+
]);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe("given several ranges that exclude the versions Lens serves, when checked", () => {
|
|
105
|
+
let exitCode: number;
|
|
106
|
+
|
|
107
|
+
beforeEach(() => {
|
|
108
|
+
givenLensServes({ react: "19.2.0", mobx: "6.13.0", "@k8slens/injectable": "26.0.0" });
|
|
109
|
+
|
|
110
|
+
givenPackageJson({
|
|
111
|
+
dependencies: { react: "^19.3.1", "@k8slens/injectable": "^26.0.0" },
|
|
112
|
+
peerDependencies: { mobx: "^7.0.0" },
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
exitCode = check();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("fails", () => {
|
|
119
|
+
expect(exitCode).toBe(1);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("lists every one of them", () => {
|
|
123
|
+
expect(logged.join("\n")).toContain(
|
|
124
|
+
[
|
|
125
|
+
` in dependencies, "react": "^19.3.1" does not include Lens's 19.2.0, declare "^19.2.0"`,
|
|
126
|
+
` in peerDependencies, "mobx": "^7.0.0" does not include Lens's 6.13.0, declare "^6.13.0"`,
|
|
127
|
+
].join("\n"),
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("given a range in dependencies that Lens does not read, as peerDependencies declares one Lens accepts, when checked", () => {
|
|
133
|
+
let exitCode: number;
|
|
134
|
+
|
|
135
|
+
beforeEach(() => {
|
|
136
|
+
givenLensServes({ react: "19.2.0" });
|
|
137
|
+
|
|
138
|
+
givenPackageJson({
|
|
139
|
+
dependencies: { react: "^19.3.1" },
|
|
140
|
+
peerDependencies: { react: "^19.0.0" },
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
exitCode = check();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("passes, as Lens would load the extension", () => {
|
|
147
|
+
expect(exitCode).toBe(0);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
describe("given a range in devDependencies only that excludes the version Lens serves, when checked", () => {
|
|
152
|
+
let exitCode: number;
|
|
153
|
+
|
|
154
|
+
beforeEach(() => {
|
|
155
|
+
givenLensServes({ react: "19.2.0" });
|
|
156
|
+
givenPackageJson({ devDependencies: { react: "^19.3.1" } });
|
|
157
|
+
|
|
158
|
+
exitCode = check();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("passes, as Lens does not read devDependencies", () => {
|
|
162
|
+
expect(exitCode).toBe(0);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("warns that the extension builds against another version than it runs on", () => {
|
|
166
|
+
expect(logged).toContain(
|
|
167
|
+
`Warning: in devDependencies, "react": "^19.3.1" does not include Lens's 19.2.0, declare "^19.2.0". The extension builds against another version than it runs on.`,
|
|
168
|
+
);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe("given ranges that exclude the versions Lens serves, when fixed", () => {
|
|
173
|
+
let exitCode: number;
|
|
174
|
+
|
|
175
|
+
beforeEach(() => {
|
|
176
|
+
givenLensServes({ react: "19.2.0", mobx: "6.13.0", "@k8slens/injectable": "26.0.0" });
|
|
177
|
+
|
|
178
|
+
givenPackageJson({
|
|
179
|
+
name: "some-extension",
|
|
180
|
+
dependencies: { react: "^19.3.1", "@k8slens/injectable": "^26.0.0", "some-package": "^1.0.0" },
|
|
181
|
+
peerDependencies: { mobx: "^7.0.0" },
|
|
182
|
+
devDependencies: { react: "^19.3.1" },
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
exitCode = check({ fix: true });
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("passes", () => {
|
|
189
|
+
expect(exitCode).toBe(0);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("rewrites each of them to the caret range of the version Lens serves, leaving everything else as it was", () => {
|
|
193
|
+
expect(readFileSync(packageJsonPath, "utf-8")).toBe(
|
|
194
|
+
`${JSON.stringify(
|
|
195
|
+
{
|
|
196
|
+
name: "some-extension",
|
|
197
|
+
dependencies: { react: "^19.2.0", "@k8slens/injectable": "^26.0.0", "some-package": "^1.0.0" },
|
|
198
|
+
peerDependencies: { mobx: "^6.13.0" },
|
|
199
|
+
devDependencies: { react: "^19.2.0" },
|
|
200
|
+
},
|
|
201
|
+
null,
|
|
202
|
+
2,
|
|
203
|
+
)}\n`,
|
|
204
|
+
);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("says what it rewrote and to reinstall", () => {
|
|
208
|
+
expect(logged).toEqual([
|
|
209
|
+
`Rewrote "react" in dependencies from "^19.3.1" to "^19.2.0".`,
|
|
210
|
+
`Rewrote "mobx" in peerDependencies from "^7.0.0" to "^6.13.0".`,
|
|
211
|
+
`Rewrote "react" in devDependencies from "^19.3.1" to "^19.2.0".`,
|
|
212
|
+
`Run "npm install" so node_modules has the versions Lens serves.`,
|
|
213
|
+
]);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("when checked again, passes", () => {
|
|
217
|
+
expect(check()).toBe(0);
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("given every range includes the version Lens serves, when fixed, leaves package.json untouched", () => {
|
|
222
|
+
givenLensServes({ react: "19.2.0" });
|
|
223
|
+
writeFileSync(packageJsonPath, '{\n "dependencies": { "react": "^19.0.0" }\n}\n');
|
|
224
|
+
|
|
225
|
+
check({ fix: true });
|
|
226
|
+
|
|
227
|
+
expect(readFileSync(packageJsonPath, "utf-8")).toBe('{\n "dependencies": { "react": "^19.0.0" }\n}\n');
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("given the environment names the versions file, when the command runs with --fix in the extension's directory", () => {
|
|
231
|
+
let exitCode: number;
|
|
232
|
+
|
|
233
|
+
beforeEach(() => {
|
|
234
|
+
givenLensServes({ react: "19.2.0" });
|
|
235
|
+
givenPackageJson({ dependencies: { react: "^19.3.1" } });
|
|
236
|
+
|
|
237
|
+
jest.spyOn(process, "cwd").mockReturnValue(directory);
|
|
238
|
+
jest.spyOn(console, "log").mockImplementation(() => {});
|
|
239
|
+
process.env.LENS_EXTENSION_DEPENDENCY_VERSIONS_FILE = versionsFilePath;
|
|
240
|
+
process.argv = ["some-node", "lens-extension-dependencies-check", "--fix"];
|
|
241
|
+
|
|
242
|
+
exitCode = extensionDependenciesCheck();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
afterEach(() => {
|
|
246
|
+
jest.restoreAllMocks();
|
|
247
|
+
delete process.env.LENS_EXTENSION_DEPENDENCY_VERSIONS_FILE;
|
|
248
|
+
process.argv = originalArgv;
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it("passes", () => {
|
|
252
|
+
expect(exitCode).toBe(0);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("rewrites the range in the extension's package.json to the version in that file", () => {
|
|
256
|
+
expect(JSON.parse(readFileSync(packageJsonPath, "utf-8"))).toEqual({ dependencies: { react: "^19.2.0" } });
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import semver from "semver";
|
|
5
|
+
|
|
6
|
+
/** Overrides where the check reads the versions Lens serves, e.g. to check against another Lens than the one on this machine. */
|
|
7
|
+
export const extensionDependencyVersionsFileEnvironmentVariable = "LENS_EXTENSION_DEPENDENCY_VERSIONS_FILE";
|
|
8
|
+
|
|
9
|
+
// Lens writes this file beside its extension-development README every time it loads. The name is
|
|
10
|
+
// repeated from `extensionDependencyVersionsFileName` of Lens's dynamic-features contracts, which a
|
|
11
|
+
// published build tool cannot depend on.
|
|
12
|
+
const defaultVersionsFilePath = () =>
|
|
13
|
+
path.join(
|
|
14
|
+
homedir(),
|
|
15
|
+
".k8slens",
|
|
16
|
+
"extensions",
|
|
17
|
+
"extension-development-instructions",
|
|
18
|
+
"extension-dependency-versions.json",
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
const commandName = "lens-extension-dependencies-check";
|
|
22
|
+
|
|
23
|
+
type Section = "dependencies" | "peerDependencies" | "devDependencies";
|
|
24
|
+
|
|
25
|
+
type PackageJson = Partial<Record<Section, Record<string, string>>>;
|
|
26
|
+
|
|
27
|
+
export interface CheckExtensionDependenciesParams {
|
|
28
|
+
readonly packageJsonPath: string;
|
|
29
|
+
readonly versionsFilePath: string;
|
|
30
|
+
readonly fix: boolean;
|
|
31
|
+
readonly log: (line: string) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Mismatch {
|
|
35
|
+
readonly section: Section;
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly declaredRange: string;
|
|
38
|
+
readonly hostVersion: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// The rule Lens applies before it lets an extension require a package it serves.
|
|
42
|
+
const isSatisfied = (hostVersion: string, declaredRange: string) =>
|
|
43
|
+
semver.satisfies(hostVersion, declaredRange, { includePrerelease: true });
|
|
44
|
+
|
|
45
|
+
const describeMismatch = ({ name, declaredRange, hostVersion }: Mismatch) =>
|
|
46
|
+
`"${name}": "${declaredRange}" does not include Lens's ${hostVersion}, declare "^${hostVersion}"`;
|
|
47
|
+
|
|
48
|
+
const readVersions = (versionsFilePath: string): Record<string, string> | undefined => {
|
|
49
|
+
try {
|
|
50
|
+
return JSON.parse(readFileSync(versionsFilePath, "utf-8"));
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const mismatchesOf = (packageJson: PackageJson, versions: Record<string, string>) =>
|
|
61
|
+
(["dependencies", "peerDependencies", "devDependencies"] as const).flatMap((section) =>
|
|
62
|
+
Object.entries(packageJson[section] ?? {}).flatMap(([name, declaredRange]): Mismatch[] => {
|
|
63
|
+
const hostVersion = versions[name];
|
|
64
|
+
|
|
65
|
+
return hostVersion !== undefined && !isSatisfied(hostVersion, declaredRange)
|
|
66
|
+
? [{ section, name, declaredRange, hostVersion }]
|
|
67
|
+
: [];
|
|
68
|
+
}),
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const indentationOf = (json: string) => /^([ \t]+)"/m.exec(json)?.[1] ?? 2;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Checks the ranges an extension's package.json declares for the packages Lens serves to
|
|
75
|
+
* extensions against the versions the Lens on this machine serves, with the rule Lens applies
|
|
76
|
+
* before loading the extension. A range Lens would refuse in `dependencies` or `peerDependencies`
|
|
77
|
+
* fails the check; one in `devDependencies` only warns, as Lens never reads those. With `fix`,
|
|
78
|
+
* rewrites every such range, in all three, to the caret range of the version Lens serves.
|
|
79
|
+
*
|
|
80
|
+
* @returns the exit code: 0 when Lens would load the extension, or when there is nothing to check against.
|
|
81
|
+
*/
|
|
82
|
+
export const checkExtensionDependencies = ({
|
|
83
|
+
packageJsonPath,
|
|
84
|
+
versionsFilePath,
|
|
85
|
+
fix,
|
|
86
|
+
log,
|
|
87
|
+
}: CheckExtensionDependenciesParams): number => {
|
|
88
|
+
const versions = readVersions(versionsFilePath);
|
|
89
|
+
|
|
90
|
+
if (!versions) {
|
|
91
|
+
log(
|
|
92
|
+
`Skipped checking dependency ranges against Lens: no "${versionsFilePath}", which Lens writes when it runs on this machine.`,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const packageJsonText = readFileSync(packageJsonPath, "utf-8");
|
|
99
|
+
const packageJson: PackageJson = JSON.parse(packageJsonText);
|
|
100
|
+
const mismatches = mismatchesOf(packageJson, versions);
|
|
101
|
+
|
|
102
|
+
if (fix) {
|
|
103
|
+
if (mismatches.length === 0) {
|
|
104
|
+
log("Nothing to fix: every dependency range includes the version Lens serves.");
|
|
105
|
+
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
for (const { section, name, declaredRange, hostVersion } of mismatches) {
|
|
110
|
+
packageJson[section] = { ...packageJson[section], [name]: `^${hostVersion}` };
|
|
111
|
+
log(`Rewrote "${name}" in ${section} from "${declaredRange}" to "^${hostVersion}".`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, indentationOf(packageJsonText))}\n`);
|
|
115
|
+
log('Run "npm install" so node_modules has the versions Lens serves.');
|
|
116
|
+
|
|
117
|
+
return 0;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Lens reads the range from peerDependencies over dependencies, as the extension declares it there.
|
|
121
|
+
const refusedByLens = mismatches.filter(
|
|
122
|
+
({ section, name }) =>
|
|
123
|
+
section === "peerDependencies" || (section === "dependencies" && !packageJson.peerDependencies?.[name]),
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const devOnly = mismatches.filter(({ section }) => section === "devDependencies");
|
|
127
|
+
|
|
128
|
+
for (const mismatch of devOnly) {
|
|
129
|
+
log(
|
|
130
|
+
`Warning: in devDependencies, ${describeMismatch(mismatch)}. The extension builds against another version than it runs on.`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (refusedByLens.length === 0) {
|
|
135
|
+
log(`Every dependency range includes the version Lens serves (read from "${versionsFilePath}").`);
|
|
136
|
+
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
log(
|
|
141
|
+
[
|
|
142
|
+
`Lens would refuse to load this extension. These ranges in package.json do not include the version Lens serves (read from "${versionsFilePath}"):`,
|
|
143
|
+
...refusedByLens.map((mismatch) => ` in ${mismatch.section}, ${describeMismatch(mismatch)}`),
|
|
144
|
+
`Run "npx ${commandName} --fix" to rewrite them, then "npm install".`,
|
|
145
|
+
].join("\n"),
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
return 1;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/** The `lens-extension-dependencies-check [--fix]` command, run in the extension's directory. */
|
|
152
|
+
export const extensionDependenciesCheck = (): number =>
|
|
153
|
+
checkExtensionDependencies({
|
|
154
|
+
packageJsonPath: path.resolve(process.cwd(), "package.json"),
|
|
155
|
+
versionsFilePath: process.env[extensionDependencyVersionsFileEnvironmentVariable] || defaultVersionsFilePath(),
|
|
156
|
+
fix: process.argv.slice(2).includes("--fix"),
|
|
157
|
+
log: (line) => console.log(line),
|
|
158
|
+
});
|
package/src/package-build.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { type Plugin, build } from "esbuild";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import { sassPlugin, postcssModules } from "esbuild-sass-plugin";
|
|
4
3
|
import { readFileSync } from "node:fs";
|
|
5
4
|
import { builtinModules as rawBuiltinModules } from "node:module";
|
|
6
5
|
import yargs from "yargs";
|
|
7
6
|
import { globImportPlugin } from "./glob-import-plugin";
|
|
8
|
-
import
|
|
7
|
+
import { stylesheetPlugin } from "./stylesheet-plugin";
|
|
9
8
|
import { partition } from "lodash";
|
|
10
9
|
|
|
11
10
|
const CWD = process.cwd();
|
|
@@ -199,22 +198,15 @@ export const packageBuild = async () => {
|
|
|
199
198
|
target: "node16",
|
|
200
199
|
sourcemap: "inline",
|
|
201
200
|
plugins: [
|
|
201
|
+
// First: a dependency's stylesheet is compiled into the bundle, not left external.
|
|
202
|
+
stylesheetPlugin({
|
|
203
|
+
packageName: packageJson.name,
|
|
204
|
+
packageDirectory: CWD,
|
|
205
|
+
declaredDependencies: new Set(Object.keys(packageJson.dependencies ?? {})),
|
|
206
|
+
}),
|
|
202
207
|
ensureCorrectImportsPlugin,
|
|
203
208
|
externalImagesPlugin,
|
|
204
209
|
globImportPlugin(),
|
|
205
|
-
sassPlugin({
|
|
206
|
-
filter: /\.module\.scss$/,
|
|
207
|
-
transform: postcssModules(
|
|
208
|
-
{
|
|
209
|
-
basedir: __dirname,
|
|
210
|
-
generateScopedName: "[name]__[local]___[hash:base64:5]",
|
|
211
|
-
},
|
|
212
|
-
[tailwindcss],
|
|
213
|
-
),
|
|
214
|
-
}),
|
|
215
|
-
sassPlugin({
|
|
216
|
-
filter: /\.scss$/,
|
|
217
|
-
}),
|
|
218
210
|
nativeNodeModulesPlugin,
|
|
219
211
|
],
|
|
220
212
|
loader: {
|