@k8slens/typescript 7.3.1 → 8.0.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/CHANGELOG.md CHANGED
@@ -1,3 +1,32 @@
1
+ ## [8.0.0](https://github.com/lensapp/lens-desktop-monorepo/compare/@k8slens/typescript@7.3.1...@k8slens/typescript@8.0.0) (2026-09-28)
2
+
3
+
4
+ ### ⚠ BREAKING CHANGES
5
+
6
+ * **package-build:** a stylesheet imported from a dependency is no longer left as
7
+ an external import for the application bundle; the importing package must
8
+ declare the dependency and register the stylesheet through its Feature.
9
+
10
+ (cherry picked from commit e3e75ae5fcd7ea07e7bc321c4975054707495de9)
11
+ (cherry picked from commit f757b83783c931cd10fa1a73e132a223ebbd0c06)
12
+ * **package-build:** lens-package-build no longer emits dist/index.css. A package
13
+ that imports a stylesheet must depend on @k8slens/stylesheet-contracts and
14
+ register the stylesheet glob in its Feature.
15
+
16
+ (cherry picked from commit cb0cd7e1b1a9f8b66b18856ac0d936708f76e583)
17
+ (cherry picked from commit f11a1cba32aa588339fedfb2c5332a16c7023090)
18
+
19
+ ### Features
20
+
21
+ * **package-build:** Compile stylesheets into stylesheet injectables ([cc49c82](https://github.com/lensapp/lens-desktop-monorepo/commit/cc49c829f443d5461b4837cef87c2ec788f9549f))
22
+ * **package-build:** Compile the stylesheets of dependencies into stylesheet injectables ([e58869f](https://github.com/lensapp/lens-desktop-monorepo/commit/e58869f8e51e024ef1092c2d34e72467e2b63d92))
23
+ * **typescript:** Type the class names of css modules ([764fa1b](https://github.com/lensapp/lens-desktop-monorepo/commit/764fa1b4a6149afa5381edd97165ce458db4e25f))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **typescript:** Read a css module's declaration instead of checking for it first ([d3d5358](https://github.com/lensapp/lens-desktop-monorepo/commit/d3d53585230582837bc1d7c7330697b27ddc2687))
29
+
1
30
  ## [7.3.1](https://github.com/lensapp/lens-desktop-monorepo/compare/@k8slens/typescript@7.3.0...@k8slens/typescript@7.3.1) (2026-09-25)
2
31
 
3
32
 
package/bin/build-types CHANGED
@@ -21,6 +21,7 @@ const pipeline = async (value, ...fns) => {
21
21
  return acc;
22
22
  };
23
23
  const yargs = require("yargs");
24
+ const { generateCssModuleTypes } = require("../lib/css-module-types");
24
25
 
25
26
  const exec = util.promisify(child_process.exec);
26
27
  const exists = util.promisify(existsWithCallback);
@@ -113,10 +114,15 @@ const main = async () => {
113
114
  })
114
115
  .parseSync(process.argv);
115
116
 
117
+ // Before either tsc: a css module's classes are typed by a generated sibling
118
+ // declaration, which has to exist for the compiler to prefer it over the
119
+ // loose wildcard.
120
+ await generateCssModuleTypes([process.cwd()]);
121
+
116
122
  if (parsedArgs.checkTypesTests) {
117
123
  await typeCheckTestFiles();
118
124
  } else {
119
- const packageJson = json5.parse(await readFile("./package.json", "utf-8"));
125
+ const packageJson = json5.parse(await readFile("./package.json", "utf-8"));
120
126
 
121
127
  await checkTsconfig(parsedArgs);
122
128
  await compileTypes();
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env node
2
+
3
+ // lens-css-module-types [directory ...]
4
+ //
5
+ // Generates a typed declaration next to every css module under the given
6
+ // directories (the current one by default). lens-types-build runs this for the
7
+ // package it builds; the monorepo root runs it over every workspace before its
8
+ // solution-wide type build.
9
+ const { generateCssModuleTypes } = require("../lib/css-module-types");
10
+
11
+ const directories = process.argv.slice(2);
12
+
13
+ generateCssModuleTypes(directories.length > 0 ? directories : [process.cwd()])
14
+ .then(({ files, written }) => {
15
+ if (written > 0) {
16
+ console.log(`css module types: ${written} of ${files} declarations written`);
17
+ }
18
+ })
19
+ .catch((error) => {
20
+ console.error(error.message ?? error);
21
+ process.exit(1);
22
+ });
@@ -7,37 +7,45 @@ declare module "win-ca/api";
7
7
 
8
8
  // Support import for custom module extensions
9
9
  // https://www.typescriptlang.org/docs/handbook/modules.html#wildcard-module-declarations
10
+ // Every stylesheet module exports `stylesheet`: the stylesheet as an injectable,
11
+ // emitted by lens-package-build. A Feature registers its own through the
12
+ // stylesheet glob below; a stylesheet imported from a dependency is re-exported
13
+ // from an *.injectable.ts file so that the Feature registers it too.
10
14
  declare module "*.module.scss" {
11
15
  const classes: { [key: string]: string };
12
16
  export default classes;
17
+ export const stylesheet: object;
13
18
  }
14
19
  declare module "*.module.css" {
15
20
  const classes: { [key: string]: string };
16
21
  export default classes;
22
+ export const stylesheet: object;
17
23
  }
18
24
  declare module "*.(ts|tsx)" {
19
25
  const modules: object[];
20
26
  export default modules;
21
27
  export const filenames: string[];
22
28
  }
29
+ // The stylesheet glob of a Feature: lens-package-build compiles every matching
30
+ // file into a module exporting a stylesheet injectable (and, for a css module,
31
+ // its class names as the default export).
32
+ declare module "*.(scss|css)" {
33
+ const modules: object[];
34
+ export default modules;
35
+ export const filenames: string[];
36
+ }
23
37
  declare module "*.(yml|yml.hb)" {
24
38
  const modules: { default: string }[];
25
39
  export default modules;
26
40
  export const filenames: string[];
27
41
  }
28
42
  declare module "*.scss" {
29
- const content: string;
30
- export = content;
43
+ export const stylesheet: object;
31
44
  }
32
45
  declare module "*.css" {
33
- const content: string;
34
- export = content;
46
+ export const stylesheet: object;
35
47
  }
36
48
 
37
- // Packages expose their bundled stylesheet through a "./styles" (or "./tailwind-styles") export
38
- // that resolves to a plain .css file, so it carries no type declarations of its own.
39
- declare module "*/styles";
40
- declare module "*/tailwind-styles";
41
49
 
42
50
  // Declare everything what's bundled as webpack's type="asset/resource"
43
51
  // Should be mocked for tests support in jestConfig.moduleNameMapper (currently in "/package.json")
@@ -0,0 +1,134 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const { pathToFileURL } = require("url");
4
+ const sass = require("sass");
5
+ const postcss = require("postcss");
6
+ const postcssModules = require("postcss-modules");
7
+
8
+ const isModuleFile = /\.module\.(scss|css)$/;
9
+ const skippedDirectories = new Set(["node_modules", "dist", "coverage", "__fixtures__", ".nx", ".git"]);
10
+
11
+ /**
12
+ * Every css module under `directory`, skipping what is never source.
13
+ */
14
+ const findModuleFiles = (directory, found = []) => {
15
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
16
+ if (entry.isDirectory()) {
17
+ if (!skippedDirectories.has(entry.name)) {
18
+ findModuleFiles(path.join(directory, entry.name), found);
19
+ }
20
+ } else if (isModuleFile.test(entry.name)) {
21
+ found.push(path.join(directory, entry.name));
22
+ }
23
+ }
24
+
25
+ return found;
26
+ };
27
+
28
+ // `@import "~some-package/some/file"` reaches into a dependency; find the package
29
+ // the way node would from the stylesheet's own directory. The same resolution
30
+ // lives in @k8slens/package-build's stylesheet plugin, which cannot be shared
31
+ // from here without a dependency cycle between the two build tools.
32
+ const findInNodeModules = (packageName, from) => {
33
+ for (let directory = from; ; directory = path.dirname(directory)) {
34
+ const candidate = path.join(directory, "node_modules", packageName);
35
+
36
+ if (fs.existsSync(candidate)) {
37
+ return candidate;
38
+ }
39
+
40
+ if (path.dirname(directory) === directory) {
41
+ return undefined;
42
+ }
43
+ }
44
+ };
45
+
46
+ const tildeImporter = (from) => ({
47
+ findFileUrl: (url) => {
48
+ if (!url.startsWith("~")) {
49
+ return null;
50
+ }
51
+
52
+ const specifier = url.slice(1);
53
+ const segments = specifier.split("/");
54
+ const packageNameLength = specifier.startsWith("@") ? 2 : 1;
55
+ const packageRoot = findInNodeModules(segments.slice(0, packageNameLength).join("/"), from);
56
+
57
+ return packageRoot ? pathToFileURL(path.join(packageRoot, ...segments.slice(packageNameLength))) : null;
58
+ },
59
+ });
60
+
61
+ /**
62
+ * The class names a css module exports, in source order.
63
+ */
64
+ const classNamesOf = async (file) => {
65
+ const { css } = sass.compile(file, { logger: sass.Logger.silent, importers: [tildeImporter(path.dirname(file))] });
66
+
67
+ let classNames = {};
68
+
69
+ await postcss([
70
+ postcssModules({
71
+ generateScopedName: "[local]",
72
+ getJSON: (_cssFileName, json) => {
73
+ classNames = json;
74
+ },
75
+ }),
76
+ ]).process(css, { from: file, map: false });
77
+
78
+ return Object.keys(classNames);
79
+ };
80
+
81
+ const declarationFor = (file, classNames) =>
82
+ [
83
+ `// Generated by lens-types-build from ${path.basename(file)}. Do not edit: it is regenerated on every`,
84
+ "// type build and ignored by git. Each class the stylesheet defines is a property here.",
85
+ "declare const classes: {",
86
+ ...classNames.map((name) => ` readonly ${JSON.stringify(name)}: string;`),
87
+ "};",
88
+ "export default classes;",
89
+ "export const stylesheet: object;",
90
+ "",
91
+ ].join("\n");
92
+
93
+ // Read rather than checked first, so that the file cannot come or go between the two.
94
+ const readIfExists = (file) => {
95
+ try {
96
+ return fs.readFileSync(file, "utf8");
97
+ } catch (error) {
98
+ if (error.code === "ENOENT") {
99
+ return undefined;
100
+ }
101
+
102
+ throw error;
103
+ }
104
+ };
105
+
106
+ /**
107
+ * Writes a `<name>.module.scss.d.ts` (or `.module.css.d.ts`) next to every css
108
+ * module under the given directories, naming exactly the classes it defines,
109
+ * so that a typo in `styles.someClass` is a type error rather than an
110
+ * unstyled element. TypeScript prefers the sibling declaration over the
111
+ * loose `*.module.scss` wildcard, which stays as the fallback for a module
112
+ * whose declaration has not been generated yet. Unchanged files are left
113
+ * alone, so incremental type builds stay incremental.
114
+ */
115
+ const generateCssModuleTypes = async (directories) => {
116
+ const files = directories.flatMap((directory) => findModuleFiles(path.resolve(directory)));
117
+ let written = 0;
118
+
119
+ for (const file of files) {
120
+ const declarationPath = `${file}.d.ts`;
121
+ const declaration = declarationFor(file, await classNamesOf(file));
122
+
123
+ if (readIfExists(declarationPath) === declaration) {
124
+ continue;
125
+ }
126
+
127
+ fs.writeFileSync(declarationPath, declaration);
128
+ written++;
129
+ }
130
+
131
+ return { files: files.length, written };
132
+ };
133
+
134
+ module.exports = { generateCssModuleTypes, findModuleFiles, classNamesOf, declarationFor };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@k8slens/typescript",
3
- "version": "7.3.1",
3
+ "version": "8.0.0",
4
4
  "lens": {
5
5
  "env": "agnostic",
6
6
  "layer": "infrastructure",
@@ -19,10 +19,12 @@
19
19
  "type": "commonjs",
20
20
  "bin": {
21
21
  "lens-types-build": "bin/build-types",
22
- "lens-types-check": "bin/types-check"
22
+ "lens-types-check": "bin/types-check",
23
+ "lens-css-module-types": "bin/css-module-types"
23
24
  },
24
25
  "files": [
25
26
  "bin",
27
+ "lib",
26
28
  "config",
27
29
  "CHANGELOG.md"
28
30
  ],
@@ -32,6 +34,9 @@
32
34
  "dependencies": {
33
35
  "json5": "^2.2.3",
34
36
  "lodash": "^4.17.21",
37
+ "postcss": "^8.5.18",
38
+ "postcss-modules": "^6.0.1",
39
+ "sass": "^1.89.0",
35
40
  "typescript-native": "npm:typescript@~7.0.2",
36
41
  "yargs": "^17.7.2"
37
42
  },
@@ -1,13 +0,0 @@
1
- // Support import for custom module extensions
2
- // https://www.typescriptlang.org/docs/handbook/modules.html#wildcard-module-declarations
3
-
4
- declare module "*.module.scss" {
5
- const classes: { [key: string]: string };
6
- export default classes;
7
- }
8
-
9
- declare module "*.scss" {
10
- const content: string;
11
- export = content;
12
- }
13
-