@knighted/css 1.0.0-rc.0 → 1.0.0-rc.10

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.
Files changed (51) hide show
  1. package/bin/generate-types.js +31 -0
  2. package/dist/cjs/css.cjs +107 -25
  3. package/dist/cjs/css.d.cts +10 -6
  4. package/dist/cjs/generateTypes.cjs +636 -0
  5. package/dist/cjs/generateTypes.d.cts +104 -0
  6. package/dist/cjs/loader.cjs +128 -56
  7. package/dist/cjs/loader.d.cts +5 -0
  8. package/dist/cjs/loaderInternals.cjs +108 -0
  9. package/dist/cjs/loaderInternals.d.cts +23 -0
  10. package/dist/cjs/moduleGraph.cjs +431 -0
  11. package/dist/cjs/moduleGraph.d.cts +15 -0
  12. package/dist/cjs/moduleInfo.cjs +62 -0
  13. package/dist/cjs/moduleInfo.d.cts +10 -0
  14. package/dist/cjs/sassInternals.cjs +135 -0
  15. package/dist/cjs/sassInternals.d.cts +25 -0
  16. package/dist/cjs/stableNamespace.cjs +12 -0
  17. package/dist/cjs/stableNamespace.d.cts +3 -0
  18. package/dist/cjs/stableSelectors.cjs +44 -0
  19. package/dist/cjs/stableSelectors.d.cts +13 -0
  20. package/dist/cjs/stableSelectorsLiteral.cjs +104 -0
  21. package/dist/cjs/stableSelectorsLiteral.d.cts +19 -0
  22. package/dist/cjs/types.cjs +2 -0
  23. package/dist/cjs/types.d.cts +4 -0
  24. package/dist/css.d.ts +10 -6
  25. package/dist/css.js +107 -26
  26. package/dist/generateTypes.d.ts +104 -0
  27. package/dist/generateTypes.js +628 -0
  28. package/dist/loader.d.ts +5 -0
  29. package/dist/loader.js +127 -55
  30. package/dist/loaderInternals.d.ts +23 -0
  31. package/dist/loaderInternals.js +96 -0
  32. package/dist/moduleGraph.d.ts +15 -0
  33. package/dist/moduleGraph.js +425 -0
  34. package/dist/moduleInfo.d.ts +10 -0
  35. package/dist/moduleInfo.js +55 -0
  36. package/dist/sassInternals.d.ts +25 -0
  37. package/dist/sassInternals.js +124 -0
  38. package/dist/stableNamespace.d.ts +3 -0
  39. package/dist/stableNamespace.js +8 -0
  40. package/dist/stableSelectors.d.ts +13 -0
  41. package/dist/stableSelectors.js +36 -0
  42. package/dist/stableSelectorsLiteral.d.ts +19 -0
  43. package/dist/stableSelectorsLiteral.js +98 -0
  44. package/dist/types.d.ts +4 -0
  45. package/dist/types.js +1 -0
  46. package/loader-queries.d.ts +61 -0
  47. package/package.json +58 -8
  48. package/stable/_index.scss +57 -0
  49. package/stable/stable.css +15 -0
  50. package/types-stub/index.d.ts +5 -0
  51. package/types.d.ts +4 -0
@@ -0,0 +1,36 @@
1
+ const DEFAULT_NAMESPACE = 'knighted';
2
+ const defaultJoin = (values) => values.filter(Boolean).join(' ');
3
+ const normalizeToken = (token) => {
4
+ const sanitized = token
5
+ .trim()
6
+ .replace(/\s+/g, '-')
7
+ .replace(/[^A-Za-z0-9_-]/g, '-')
8
+ .replace(/-+/g, '-')
9
+ .replace(/^-|-$/g, '');
10
+ return sanitized.length ? sanitized : 'stable';
11
+ };
12
+ export function stableToken(token, options) {
13
+ const normalized = normalizeToken(token);
14
+ const namespace = options?.namespace?.trim() ?? DEFAULT_NAMESPACE;
15
+ if (!namespace) {
16
+ return normalized;
17
+ }
18
+ return `${namespace}-${normalized}`;
19
+ }
20
+ export function stableClass(token, options) {
21
+ return stableToken(token, options);
22
+ }
23
+ export function stableSelector(token, options) {
24
+ return `.${stableToken(token, options)}`;
25
+ }
26
+ export function createStableClassFactory(options) {
27
+ return (token) => stableClass(token, options);
28
+ }
29
+ export function stableClassName(styles, key, options) {
30
+ const hashed = styles[key] ?? '';
31
+ const token = options?.token ?? String(key);
32
+ const stable = stableClass(token, options);
33
+ const join = options?.join ?? defaultJoin;
34
+ return join([hashed, stable]);
35
+ }
36
+ export const stableClassFromModule = stableClassName;
@@ -0,0 +1,19 @@
1
+ export interface StableSelectorsLiteralResult {
2
+ literal: string;
3
+ selectorMap: Map<string, string>;
4
+ }
5
+ export declare function buildStableSelectorsLiteral(options: {
6
+ css: string;
7
+ namespace: string;
8
+ resourcePath: string;
9
+ emitWarning: (message: string) => void;
10
+ }): StableSelectorsLiteralResult;
11
+ export declare function collectStableSelectors(css: string, namespace: string, filename?: string): Map<string, string>;
12
+ declare function collectStableSelectorsByRegex(css: string, namespace: string): Map<string, string>;
13
+ export declare function formatStableSelectorMap(map: Map<string, string>): string;
14
+ export declare const __stableSelectorsLiteralInternals: {
15
+ collectStableSelectors: typeof collectStableSelectors;
16
+ collectStableSelectorsByRegex: typeof collectStableSelectorsByRegex;
17
+ formatStableSelectorMap: typeof formatStableSelectorMap;
18
+ };
19
+ export {};
@@ -0,0 +1,98 @@
1
+ import { transform as lightningTransform } from 'lightningcss';
2
+ import { escapeRegex, serializeSelector } from './helpers.js';
3
+ export function buildStableSelectorsLiteral(options) {
4
+ const trimmedNamespace = options.namespace.trim();
5
+ if (!trimmedNamespace) {
6
+ options.emitWarning(`stableSelectors requested for ${options.resourcePath} but "stableNamespace" resolved to an empty value.`);
7
+ return {
8
+ literal: 'export const stableSelectors = {} as const;\n',
9
+ selectorMap: new Map(),
10
+ };
11
+ }
12
+ const selectorMap = collectStableSelectors(options.css, trimmedNamespace, options.resourcePath);
13
+ if (selectorMap.size === 0) {
14
+ options.emitWarning(`stableSelectors requested for ${options.resourcePath} but no selectors matched namespace "${trimmedNamespace}".`);
15
+ }
16
+ return {
17
+ literal: `export const stableSelectors = ${formatStableSelectorMap(selectorMap)} as const;\n`,
18
+ selectorMap,
19
+ };
20
+ }
21
+ export function collectStableSelectors(css, namespace, filename) {
22
+ if (!namespace)
23
+ return new Map();
24
+ const astResult = collectStableSelectorsFromAst(css, namespace, filename);
25
+ if (astResult) {
26
+ return astResult;
27
+ }
28
+ return collectStableSelectorsByRegex(css, namespace);
29
+ }
30
+ function collectStableSelectorsFromAst(css, namespace, filename) {
31
+ try {
32
+ const tokens = new Map();
33
+ const escaped = escapeRegex(namespace);
34
+ const pattern = new RegExp(`\\.${escaped}-([A-Za-z0-9_-]+)`, 'g');
35
+ lightningTransform({
36
+ filename: filename ?? 'knighted-types-probe.css',
37
+ code: Buffer.from(css),
38
+ minify: false,
39
+ visitor: {
40
+ Rule: {
41
+ style(rule) {
42
+ const target = Array.isArray(rule?.selectors)
43
+ ? rule
44
+ : rule?.value && Array.isArray(rule.value.selectors)
45
+ ? rule.value
46
+ : undefined;
47
+ if (!target)
48
+ return rule;
49
+ for (const selector of target.selectors) {
50
+ const selectorStr = serializeSelector(selector);
51
+ pattern.lastIndex = 0;
52
+ let match;
53
+ while ((match = pattern.exec(selectorStr)) !== null) {
54
+ const token = match[1];
55
+ if (!token)
56
+ continue;
57
+ tokens.set(token, `${namespace}-${token}`);
58
+ }
59
+ }
60
+ return rule;
61
+ },
62
+ },
63
+ },
64
+ });
65
+ return tokens;
66
+ }
67
+ catch {
68
+ return undefined;
69
+ }
70
+ }
71
+ function collectStableSelectorsByRegex(css, namespace) {
72
+ const escaped = escapeRegex(namespace);
73
+ const pattern = new RegExp(`\\.${escaped}-([A-Za-z0-9_-]+)`, 'g');
74
+ const tokens = new Map();
75
+ let match;
76
+ while ((match = pattern.exec(css)) !== null) {
77
+ const token = match[1];
78
+ if (!token)
79
+ continue;
80
+ tokens.set(token, `${namespace}-${token}`);
81
+ }
82
+ return tokens;
83
+ }
84
+ export function formatStableSelectorMap(map) {
85
+ if (map.size === 0) {
86
+ return 'Object.freeze({})';
87
+ }
88
+ const entries = Array.from(map.entries()).sort(([a], [b]) => a.localeCompare(b));
89
+ const lines = entries.map(([token, selector]) => {
90
+ return ` ${JSON.stringify(token)}: ${JSON.stringify(selector)}`;
91
+ });
92
+ return `Object.freeze({\n${lines.join(',\n')}\n})`;
93
+ }
94
+ export const __stableSelectorsLiteralInternals = {
95
+ collectStableSelectors,
96
+ collectStableSelectorsByRegex,
97
+ formatStableSelectorMap,
98
+ };
@@ -0,0 +1,4 @@
1
+ export type CssResolver = (specifier: string, ctx: {
2
+ cwd: string;
3
+ from?: string;
4
+ }) => string | Promise<string | undefined>;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Ambient declaration for loader query imports like "./file.js?knighted-css".
3
+ * The loader appends a named export `knightedCss` containing the compiled CSS.
4
+ */
5
+ declare module '*?knighted-css' {
6
+ export const knightedCss: string
7
+ }
8
+
9
+ type KnightedCssStableSelectorMap = Readonly<Record<string, string>>
10
+
11
+ declare module '*?knighted-css&types' {
12
+ export const knightedCss: string
13
+ export const stableSelectors: KnightedCssStableSelectorMap
14
+ }
15
+
16
+ /**
17
+ * Ambient declaration for combined loader imports (e.g. "./file.tsx?knighted-css&combined").
18
+ * These modules behave like the original module with an additional `knightedCss` export.
19
+ * TypeScript cannot infer the underlying module automatically, so consumers can
20
+ * import the default export and narrow it with `KnightedCssCombinedModule<typeof import('./file')>`.
21
+ */
22
+ type KnightedCssCombinedModule<TModule> = TModule & { knightedCss: string }
23
+
24
+ declare module '*?knighted-css&combined' {
25
+ const combined: KnightedCssCombinedModule<Record<string, unknown>>
26
+ export default combined
27
+ export const knightedCss: string
28
+ }
29
+
30
+ declare module '*?knighted-css&combined&named-only' {
31
+ const combined: KnightedCssCombinedModule<Record<string, unknown>>
32
+ export default combined
33
+ export const knightedCss: string
34
+ }
35
+
36
+ declare module '*?knighted-css&combined&no-default' {
37
+ const combined: KnightedCssCombinedModule<Record<string, unknown>>
38
+ export default combined
39
+ export const knightedCss: string
40
+ }
41
+
42
+ declare module '*?knighted-css&combined&types' {
43
+ const combined: KnightedCssCombinedModule<Record<string, unknown>>
44
+ export default combined
45
+ export const knightedCss: string
46
+ export const stableSelectors: KnightedCssStableSelectorMap
47
+ }
48
+
49
+ declare module '*?knighted-css&combined&named-only&types' {
50
+ const combined: KnightedCssCombinedModule<Record<string, unknown>>
51
+ export default combined
52
+ export const knightedCss: string
53
+ export const stableSelectors: KnightedCssStableSelectorMap
54
+ }
55
+
56
+ declare module '*?knighted-css&combined&no-default&types' {
57
+ const combined: KnightedCssCombinedModule<Record<string, unknown>>
58
+ export default combined
59
+ export const knightedCss: string
60
+ export const stableSelectors: KnightedCssStableSelectorMap
61
+ }
package/package.json CHANGED
@@ -1,13 +1,29 @@
1
1
  {
2
2
  "name": "@knighted/css",
3
- "version": "1.0.0-rc.0",
3
+ "version": "1.0.0-rc.10",
4
4
  "description": "A build-time utility that traverses JavaScript/TypeScript module dependency graphs to extract, compile, and optimize all imported CSS into a single, in-memory string.",
5
5
  "type": "module",
6
6
  "main": "./dist/css.js",
7
- "types": "./dist/css.d.ts",
7
+ "types": "./types.d.ts",
8
+ "typesVersions": {
9
+ "*": {
10
+ "loader": [
11
+ "./dist/loader.d.ts"
12
+ ],
13
+ "loader-queries": [
14
+ "./loader-queries.d.ts"
15
+ ],
16
+ "generate-types": [
17
+ "./dist/generateTypes.d.ts"
18
+ ],
19
+ "*": [
20
+ "./types.d.ts"
21
+ ]
22
+ }
23
+ },
8
24
  "exports": {
9
25
  ".": {
10
- "types": "./dist/css.d.ts",
26
+ "types": "./types.d.ts",
11
27
  "import": "./dist/css.js",
12
28
  "require": "./dist/cjs/css.cjs"
13
29
  },
@@ -15,6 +31,27 @@
15
31
  "types": "./dist/loader.d.ts",
16
32
  "import": "./dist/loader.js",
17
33
  "require": "./dist/cjs/loader.cjs"
34
+ },
35
+ "./loader-queries": {
36
+ "types": "./loader-queries.d.ts",
37
+ "default": "./loader-queries.d.ts"
38
+ },
39
+ "./generate-types": {
40
+ "types": "./dist/generateTypes.d.ts",
41
+ "import": "./dist/generateTypes.js",
42
+ "default": "./dist/generateTypes.js"
43
+ },
44
+ "./stableSelectors": {
45
+ "types": "./dist/stableSelectors.d.ts",
46
+ "import": "./dist/stableSelectors.js",
47
+ "require": "./dist/cjs/stableSelectors.cjs"
48
+ },
49
+ "./stable": {
50
+ "sass": "./stable/_index.scss",
51
+ "default": "./stable/_index.scss"
52
+ },
53
+ "./stable/stable.css": {
54
+ "default": "./stable/stable.css"
18
55
  }
19
56
  },
20
57
  "keywords": [
@@ -29,15 +66,23 @@
29
66
  "vanilla-extract",
30
67
  "lightningcss"
31
68
  ],
69
+ "bin": {
70
+ "knighted-css-generate-types": "./bin/generate-types.js"
71
+ },
32
72
  "scripts": {
33
- "build": "duel",
34
- "check-types": "tsc --noEmit",
73
+ "build": "duel && node ./scripts/copy-types-stub.js",
74
+ "check-types": "tsc --noEmit --project tsconfig.json && tsc --noEmit --project tsconfig.tests.json",
35
75
  "test": "c8 --reporter=text --reporter=text-summary --reporter=lcov --include \"src/**/*.ts\" tsx --test test/**/*.test.ts",
36
76
  "prepack": "npm run build"
37
77
  },
38
78
  "dependencies": {
39
- "dependency-tree": "^11.2.0",
40
- "lightningcss": "^1.30.2"
79
+ "es-module-lexer": "^2.0.0",
80
+ "lightningcss": "^1.30.2",
81
+ "node-module-type": "^1.0.1",
82
+ "get-tsconfig": "^4.13.0",
83
+ "oxc-parser": "^0.104.0",
84
+ "oxc-resolver": "^11.16.0",
85
+ "tsconfig-paths": "^4.2.0"
41
86
  },
42
87
  "peerDependencies": {
43
88
  "@vanilla-extract/integration": "^8.0.0",
@@ -56,7 +101,12 @@
56
101
  }
57
102
  },
58
103
  "files": [
59
- "dist"
104
+ "dist",
105
+ "loader-queries.d.ts",
106
+ "types.d.ts",
107
+ "stable",
108
+ "bin",
109
+ "types-stub"
60
110
  ],
61
111
  "author": "KCM <knightedcodemonkey@gmail.com>",
62
112
  "license": "MIT",
@@ -0,0 +1,57 @@
1
+ // Knighted stable selector mixins
2
+ // Usage: @use '@knighted/css/stable' as knighted;
3
+ // .button { @include knighted.stable('button') { ... } }
4
+
5
+ @use 'sass:meta';
6
+
7
+ $knighted-stable-namespace: 'knighted' !default;
8
+
9
+ @function _knighted-normalize-token($token) {
10
+ @if meta.type-of($token) == 'number' {
11
+ @return $token;
12
+ }
13
+ @return $token;
14
+ }
15
+
16
+ @function stable-token($token, $namespace: $knighted-stable-namespace) {
17
+ $normalized-token: _knighted-normalize-token($token);
18
+ @if $namespace == '' {
19
+ @return $normalized-token;
20
+ }
21
+ @return '#{$namespace}-#{$normalized-token}';
22
+ }
23
+
24
+ @function stable-class($token, $namespace: $knighted-stable-namespace) {
25
+ $token-value: stable-token($token, $namespace);
26
+ @return '.#{$token-value}';
27
+ }
28
+
29
+ @mixin stable($token, $namespace: $knighted-stable-namespace) {
30
+ @if not & {
31
+ @error 'The knighted.stable mixin must be used within a selector context so that "&" is defined.';
32
+ }
33
+
34
+ $stable-selector: stable-class($token, $namespace);
35
+ @at-root #{&},
36
+ #{$stable-selector} {
37
+ @content;
38
+ }
39
+ }
40
+
41
+ @mixin stable-at-root($selector, $token, $namespace: $knighted-stable-namespace) {
42
+ $stable-selector: stable-class($token, $namespace);
43
+ @at-root #{$selector},
44
+ #{$stable-selector} {
45
+ @content;
46
+ }
47
+ }
48
+
49
+ @function stable-class-name($token, $namespace: $knighted-stable-namespace) {
50
+ @return stable-token($token, $namespace);
51
+ }
52
+
53
+ @mixin stable-only($token, $namespace: $knighted-stable-namespace) {
54
+ @at-root #{stable-class($token, $namespace)} {
55
+ @content;
56
+ }
57
+ }
@@ -0,0 +1,15 @@
1
+ @layer knighted.stable;
2
+
3
+ :root {
4
+ --knighted-stable-namespace: 'knighted';
5
+ }
6
+
7
+ /*
8
+ Usage:
9
+ @import '@knighted/css/stable/stable.css';
10
+ @layer knighted.stable {
11
+ .knighted-button {
12
+ declarations go here;
13
+ }
14
+ }
15
+ */
@@ -0,0 +1,5 @@
1
+ // Placeholder stub for @knighted/css stable selector declarations.
2
+ // Running `knighted-css-generate-types` replaces this file with project-specific
3
+ // references into the generated `.knighted-css` manifest.
4
+
5
+ export {}
package/types.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /// <reference path="./loader-queries.d.ts" />
2
+ /// <reference path="./types-stub/index.d.ts" />
3
+
4
+ export * from './dist/css.js'