@master/css-tooling 0.0.0-site.1793659883.g69c9aebcf628

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 (122) hide show
  1. package/README.md +58 -0
  2. package/dist/browser.d.ts +2 -0
  3. package/dist/browser.js +1 -0
  4. package/dist/css-tree-version.d.ts +2 -0
  5. package/dist/css-tree-version.js +4 -0
  6. package/dist/css.d.ts +32 -0
  7. package/dist/css.js +120 -0
  8. package/dist/immutable.d.ts +2 -0
  9. package/dist/immutable.js +7 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.js +1 -0
  12. package/dist/language/binding-session.d.ts +6 -0
  13. package/dist/language/binding-session.js +8 -0
  14. package/dist/language/browser.d.ts +10 -0
  15. package/dist/language/browser.js +12 -0
  16. package/dist/language/common.d.ts +12 -0
  17. package/dist/language/common.js +55 -0
  18. package/dist/language/contracts.d.ts +197 -0
  19. package/dist/language/contracts.js +1 -0
  20. package/dist/language/index.d.ts +29 -0
  21. package/dist/language/index.js +39 -0
  22. package/dist/language/master-css.d.ts +13 -0
  23. package/dist/language/master-css.js +35 -0
  24. package/dist/language/node.d.ts +21 -0
  25. package/dist/language/node.js +36 -0
  26. package/dist/language/semantic/scopes.d.ts +55 -0
  27. package/dist/language/semantic/scopes.js +73 -0
  28. package/dist/language/semantic/types.d.ts +11 -0
  29. package/dist/language/semantic/types.js +1 -0
  30. package/dist/language/session.d.ts +37 -0
  31. package/dist/language/session.js +87 -0
  32. package/dist/language/settings.d.ts +13 -0
  33. package/dist/language/settings.js +19 -0
  34. package/dist/language/utils/mdn-css-data.d.ts +5 -0
  35. package/dist/language/utils/mdn-css-data.js +63 -0
  36. package/dist/lexer/browser.d.ts +6 -0
  37. package/dist/lexer/browser.js +11 -0
  38. package/dist/lexer/contracts.d.ts +41 -0
  39. package/dist/lexer/contracts.js +1 -0
  40. package/dist/lexer/index.d.ts +8 -0
  41. package/dist/lexer/index.js +11 -0
  42. package/dist/lexer/node.d.ts +7 -0
  43. package/dist/lexer/node.js +11 -0
  44. package/dist/lexer/session.d.ts +17 -0
  45. package/dist/lexer/session.js +25 -0
  46. package/dist/lint/analysis.d.ts +90 -0
  47. package/dist/lint/analysis.js +1 -0
  48. package/dist/lint/binding-session.d.ts +21 -0
  49. package/dist/lint/binding-session.js +97 -0
  50. package/dist/lint/constants.d.ts +7 -0
  51. package/dist/lint/constants.js +18 -0
  52. package/dist/lint/contracts.d.ts +17 -0
  53. package/dist/lint/contracts.js +6 -0
  54. package/dist/lint/diagnostic-format.d.ts +5 -0
  55. package/dist/lint/diagnostic-format.js +15 -0
  56. package/dist/lint/diagnostics.d.ts +42 -0
  57. package/dist/lint/diagnostics.js +1 -0
  58. package/dist/lint/index.d.ts +21 -0
  59. package/dist/lint/index.js +30 -0
  60. package/dist/lint/node.d.ts +6 -0
  61. package/dist/lint/node.js +11 -0
  62. package/dist/lint/rule-signatures.d.ts +23 -0
  63. package/dist/lint/rule-signatures.js +27 -0
  64. package/dist/lint/source.d.ts +70 -0
  65. package/dist/lint/source.js +261 -0
  66. package/dist/math-types.d.ts +11 -0
  67. package/dist/math-types.js +236 -0
  68. package/dist/math-validation.d.ts +7 -0
  69. package/dist/math-validation.js +74 -0
  70. package/dist/node.d.ts +12 -0
  71. package/dist/node.js +32 -0
  72. package/dist/scanner/binding-session.d.ts +29 -0
  73. package/dist/scanner/binding-session.js +37 -0
  74. package/dist/scanner/core.d.ts +130 -0
  75. package/dist/scanner/core.js +480 -0
  76. package/dist/scanner/index.d.ts +3 -0
  77. package/dist/scanner/index.js +3 -0
  78. package/dist/scanner/node.d.ts +5 -0
  79. package/dist/scanner/node.js +4 -0
  80. package/dist/scanner/options/index.d.ts +16 -0
  81. package/dist/scanner/options/index.js +57 -0
  82. package/dist/scanner/source-policy.d.ts +15 -0
  83. package/dist/scanner/source-policy.js +131 -0
  84. package/dist/source/adapters/optional-peer.d.ts +5 -0
  85. package/dist/source/adapters/optional-peer.js +29 -0
  86. package/dist/source/adapters/oxc.d.ts +2 -0
  87. package/dist/source/adapters/oxc.js +6 -0
  88. package/dist/source/adapters/svelte.d.ts +5 -0
  89. package/dist/source/adapters/svelte.js +82 -0
  90. package/dist/source/adapters/types.d.ts +11 -0
  91. package/dist/source/adapters/types.js +9 -0
  92. package/dist/source/adapters/vue.d.ts +5 -0
  93. package/dist/source/adapters/vue.js +50 -0
  94. package/dist/source/browser.d.ts +7 -0
  95. package/dist/source/browser.js +11 -0
  96. package/dist/source/contracts.d.ts +35 -0
  97. package/dist/source/contracts.js +1 -0
  98. package/dist/source/index.d.ts +8 -0
  99. package/dist/source/index.js +11 -0
  100. package/dist/source/native.d.ts +5 -0
  101. package/dist/source/native.js +53 -0
  102. package/dist/source/node.d.ts +7 -0
  103. package/dist/source/node.js +11 -0
  104. package/dist/source/session.d.ts +25 -0
  105. package/dist/source/session.js +37 -0
  106. package/dist/syntax-validation.d.ts +10 -0
  107. package/dist/syntax-validation.js +54 -0
  108. package/dist/tooling-session.d.ts +66 -0
  109. package/dist/tooling-session.js +188 -0
  110. package/dist/validator/binding-session.d.ts +17 -0
  111. package/dist/validator/binding-session.js +29 -0
  112. package/dist/validator/contracts.d.ts +24 -0
  113. package/dist/validator/contracts.js +1 -0
  114. package/dist/validator/index.d.ts +10 -0
  115. package/dist/validator/index.js +13 -0
  116. package/dist/validator/node.d.ts +6 -0
  117. package/dist/validator/node.js +11 -0
  118. package/dist/validator/types/syntax-error.d.ts +22 -0
  119. package/dist/validator/types/syntax-error.js +1 -0
  120. package/dist/value-validation.d.ts +46 -0
  121. package/dist/value-validation.js +162 -0
  122. package/package.json +127 -0
@@ -0,0 +1,57 @@
1
+ // src/scanner/options/index.ts
2
+ const defaultExclude = Object.freeze([
3
+ "**/*.css",
4
+ "**/*.d.ts",
5
+ "**/*.test.*",
6
+ "**/*test.{js,cjs,ts}",
7
+ "**/*README.md",
8
+ "**/dist/**",
9
+ "**/out/**",
10
+ "**/public/**",
11
+ "**/.git/**",
12
+ "**/.hg/**",
13
+ "**/.svn/**",
14
+ "**/.cache/**",
15
+ "**/.vite/**",
16
+ "**/.turbo/**",
17
+ "**/.parcel-cache/**",
18
+ "**/.nx/cache/**",
19
+ "**/.astro/**",
20
+ "**/.next/**",
21
+ "**/.nuxt/**",
22
+ "**/.svelte-kit/**",
23
+ "**/.vitepress/cache/**",
24
+ "**/.vitepress/dist/**",
25
+ "**/.docusaurus/**",
26
+ "**/.output/**",
27
+ "**/.vercel/**",
28
+ "**/.netlify/**",
29
+ "**/.wrangler/**",
30
+ "**/.serverless/**",
31
+ "**/.yarn/**",
32
+ "**/.pnpm-store/**",
33
+ "**/.npm/**",
34
+ "**/.bun/**",
35
+ "**/node_modules/webpack*/**",
36
+ "**/node_modules/events/**",
37
+ "**/node_modules/html-entities/**",
38
+ "**/node_modules/ansi-html-community/**",
39
+ "**/node_modules/util/**",
40
+ "**/node_modules/react/**",
41
+ "**/node_modules/react-dom/**",
42
+ "**/node_modules/vue/**",
43
+ "**/node_modules/next/**",
44
+ "**/node_modules/astro/**",
45
+ "**/node_modules/svelte/**",
46
+ "**/node_modules/svelte-hmr/**",
47
+ "**/node_modules/@swc/**",
48
+ "**/node_modules/@sveltejs/**",
49
+ "**/node_modules/@angular/**"
50
+ ]);
51
+ const defaultScannerOptions = Object.freeze({
52
+ verbose: 1,
53
+ exclude: defaultExclude,
54
+ safelist: Object.freeze([]),
55
+ blocklist: Object.freeze([])
56
+ });
57
+ export { defaultScannerOptions };
@@ -0,0 +1,15 @@
1
+ interface SourcePolicyOptions {
2
+ readonly exclude?: readonly string[];
3
+ readonly outputDirectories?: readonly string[];
4
+ }
5
+ /** Shared Node input boundary. No global Git configuration or ignore file is read. */
6
+ declare class SourcePolicy {
7
+ readonly projectDir: string;
8
+ readonly options: SourcePolicyOptions;
9
+ readonly dependencies: Set<string>;
10
+ readonly root: string;
11
+ private readonly cache;
12
+ constructor(projectDir: string, options?: SourcePolicyOptions);
13
+ accepts(source: string, explicit?: boolean): boolean;
14
+ }
15
+ export { SourcePolicy, SourcePolicyOptions };
@@ -0,0 +1,131 @@
1
+ import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { dirname, extname, isAbsolute, relative, resolve, sep } from "node:path";
3
+ import ignore from "ignore";
4
+ import { minimatch } from "minimatch";
5
+ // src/scanner/source-policy.ts
6
+ const automaticExcludes = [
7
+ "**/node_modules/**",
8
+ "**/*.d.ts",
9
+ "**/*.d.mts",
10
+ "**/*.d.cts",
11
+ "**/dist/**",
12
+ "**/out/**",
13
+ "**/.cache/**",
14
+ "**/.next/**",
15
+ "**/.nuxt/**",
16
+ "**/.output/**",
17
+ "**/.svelte-kit/**"
18
+ ];
19
+ const binaryExtensions = /* @__PURE__ */ new Set([
20
+ ".png",
21
+ ".jpg",
22
+ ".jpeg",
23
+ ".gif",
24
+ ".webp",
25
+ ".avif",
26
+ ".ico",
27
+ ".bmp",
28
+ ".woff",
29
+ ".woff2",
30
+ ".ttf",
31
+ ".otf",
32
+ ".eot",
33
+ ".pdf",
34
+ ".zip",
35
+ ".gz",
36
+ ".br",
37
+ ".wasm",
38
+ ".mp3",
39
+ ".mp4",
40
+ ".webm",
41
+ ".mov"
42
+ ]);
43
+ const neverInputs = [
44
+ "**/.git/**",
45
+ "**/.hg/**",
46
+ "**/.svn/**",
47
+ "**/.master/**"
48
+ ];
49
+ const posix = (value) => value.split(sep).join("/");
50
+ const inside = (root, file) => {
51
+ const path = relative(root, file);
52
+ return !isAbsolute(path) && path !== ".." && !path.startsWith(`..${sep}`);
53
+ };
54
+ function isWorkspace(directory) {
55
+ if (existsSync(resolve(directory, "pnpm-workspace.yaml"))) return true;
56
+ try {
57
+ const { workspaces } = JSON.parse(readFileSync(resolve(directory, "package.json"), "utf8"));
58
+ return Array.isArray(workspaces) || Array.isArray(workspaces?.packages);
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+ /** Shared Node input boundary. No global Git configuration or ignore file is read. */
64
+ var SourcePolicy = class {
65
+ projectDir;
66
+ options;
67
+ dependencies = /* @__PURE__ */ new Set();
68
+ root;
69
+ cache = /* @__PURE__ */ new Map();
70
+ constructor(projectDir, options = {}) {
71
+ this.projectDir = projectDir;
72
+ this.options = options;
73
+ this.root = resolve(projectDir);
74
+ for (let directory = resolve(projectDir);; directory = dirname(directory)) {
75
+ if (existsSync(resolve(directory, ".git")) || isWorkspace(directory)) this.root = directory;
76
+ if (dirname(directory) === directory) break;
77
+ }
78
+ }
79
+ accepts(source, explicit = false) {
80
+ const file = resolve(this.projectDir, source.split("?")[0]);
81
+ if (binaryExtensions.has(extname(file).toLowerCase())) return false;
82
+ const path = posix(file);
83
+ const matches = (pattern) => minimatch(path, pattern, { dot: true }) || minimatch(posix(relative(this.projectDir, file)), pattern, { dot: true });
84
+ if (neverInputs.some(matches) || this.options.outputDirectories?.some((directory) => inside(resolve(this.projectDir, directory), file))) return false;
85
+ if (this.options.exclude?.some(matches)) return false;
86
+ if (explicit) return true;
87
+ if (automaticExcludes.some(matches)) return false;
88
+ const directories = [];
89
+ for (let directory = dirname(file); inside(this.root, directory); directory = dirname(directory)) {
90
+ directories.unshift(directory);
91
+ if (directory === this.root) break;
92
+ }
93
+ const rules = [];
94
+ const ignored = (target, directory) => {
95
+ let result = false;
96
+ for (const rule of rules) {
97
+ const name = posix(relative(rule.directory, target)) + (directory ? "/" : "");
98
+ const match = rule.matcher.test(name);
99
+ if (match.ignored) result = true;
100
+ if (match.unignored) result = false;
101
+ }
102
+ return result;
103
+ };
104
+ for (const directory of directories) {
105
+ if (directory !== this.root && ignored(directory, true)) return false;
106
+ const filename = resolve(directory, ".gitignore");
107
+ this.dependencies.add(filename);
108
+ try {
109
+ const stat = statSync(filename);
110
+ const identity = `${stat.mtimeMs}:${stat.size}:${stat.ino}`;
111
+ let cached = this.cache.get(filename);
112
+ if (cached?.identity !== identity) {
113
+ cached = {
114
+ identity,
115
+ matcher: ignore().add(readFileSync(filename, "utf8"))
116
+ };
117
+ this.cache.set(filename, cached);
118
+ }
119
+ rules.push({
120
+ directory,
121
+ matcher: cached.matcher
122
+ });
123
+ } catch (error) {
124
+ if (error.code !== "ENOENT") throw error;
125
+ this.cache.delete(filename);
126
+ }
127
+ }
128
+ return !ignored(file, false);
129
+ }
130
+ };
131
+ export { SourcePolicy };
@@ -0,0 +1,5 @@
1
+ type OptionalPeerImporter = (specifier: string) => Promise<unknown>;
2
+ declare function loadOptionalPeer<T>(specifier: string, label: string): Promise<T | undefined>;
3
+ declare function setOptionalPeerImporterForTest(nextImporter: OptionalPeerImporter): void;
4
+ declare function resetOptionalPeerStateForTest(): void;
5
+ export { loadOptionalPeer, resetOptionalPeerStateForTest, setOptionalPeerImporterForTest };
@@ -0,0 +1,29 @@
1
+ // src/source/adapters/optional-peer.ts
2
+ const defaultImporter = (specifier) => import(specifier);
3
+ const peerPromises = /* @__PURE__ */ new Map();
4
+ const warnedPeers = /* @__PURE__ */ new Set();
5
+ let importer = defaultImporter;
6
+ async function loadOptionalPeer(specifier, label) {
7
+ let peerPromise = peerPromises.get(specifier);
8
+ if (!peerPromise) {
9
+ peerPromise = importer(specifier).catch((error) => {
10
+ if (!warnedPeers.has(specifier)) {
11
+ warnedPeers.add(specifier);
12
+ const message = error instanceof Error ? ` ${error.message}` : "";
13
+ console.warn(`[@master/css-tooling/source] Optional ${label} parser "${specifier}" could not be loaded; falling back to text extraction.${message}`);
14
+ }
15
+ });
16
+ peerPromises.set(specifier, peerPromise);
17
+ }
18
+ return await peerPromise;
19
+ }
20
+ function setOptionalPeerImporterForTest(nextImporter) {
21
+ importer = nextImporter;
22
+ peerPromises.clear();
23
+ }
24
+ function resetOptionalPeerStateForTest() {
25
+ importer = defaultImporter;
26
+ peerPromises.clear();
27
+ warnedPeers.clear();
28
+ }
29
+ export { loadOptionalPeer, resetOptionalPeerStateForTest, setOptionalPeerImporterForTest };
@@ -0,0 +1,2 @@
1
+ declare function extractOxcClasses(source: string, content: string): string[];
2
+ export { extractOxcClasses };
@@ -0,0 +1,6 @@
1
+ import { extractOxcClassesNative } from "../native.js";
2
+ // src/source/adapters/oxc.ts
3
+ function extractOxcClasses(source, content) {
4
+ return extractOxcClassesNative(source, content);
5
+ }
6
+ export { extractOxcClasses };
@@ -0,0 +1,5 @@
1
+ import { SourceAdapter } from "./types.js";
2
+ declare const SVELTE_SOURCE_EXT: RegExp;
3
+ declare function extractSvelteClasses(source: string, content: string): Promise<string[]>;
4
+ declare function svelteAdapter(): SourceAdapter;
5
+ export { SVELTE_SOURCE_EXT, extractSvelteClasses, svelteAdapter };
@@ -0,0 +1,82 @@
1
+ import { extractClassCandidatesNative } from "../native.js";
2
+ import { extractOxcClasses } from "./oxc.js";
3
+ import { loadOptionalPeer } from "./optional-peer.js";
4
+ import { MasterCSSError } from "@master/css-schema";
5
+ // src/source/adapters/svelte.ts
6
+ const SVELTE_SOURCE_EXT = /\.svelte(?:\?|$)/;
7
+ function isSvelteSource(source) {
8
+ return SVELTE_SOURCE_EXT.test(source) && !/[?&]type=style(?:&|$)/.test(source);
9
+ }
10
+ function addClassString(classes, value) {
11
+ if (!value) return;
12
+ for (const className of extractClassCandidatesNative(value)) if (className) classes.add(className);
13
+ }
14
+ function addOxc(classes, source, content) {
15
+ for (const className of extractOxcClasses(source, content)) if (className) classes.add(className);
16
+ }
17
+ function scriptExtension(content, script) {
18
+ if (script?.start == null || script.content?.start == null) return "js";
19
+ const openingTag = content.slice(script.start, script.content.start);
20
+ const match = /(?:^|\s)lang\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/iu.exec(openingTag);
21
+ const language = (match?.[1] ?? match?.[2] ?? match?.[3])?.toLowerCase();
22
+ return language === "ts" || language === "tsx" ? language : "js";
23
+ }
24
+ function visitMarkup(node, source, content, classes, extension) {
25
+ if (!node || typeof node !== "object") return;
26
+ if (Array.isArray(node.attributes)) for (const attribute of node.attributes) {
27
+ if (attribute.type === "Class") {
28
+ addClassString(classes, attribute.name);
29
+ if (attribute.expression?.start != null && attribute.expression?.end != null) addOxc(classes, `${source}.${extension}`, content.slice(attribute.expression.start, attribute.expression.end));
30
+ continue;
31
+ }
32
+ if (attribute.type !== "Attribute" || attribute.name !== "class") continue;
33
+ for (const value of attribute.value || []) if (value.type === "Text") addClassString(classes, value.data ?? value.raw);
34
+ else if (value.start != null && value.end != null) addOxc(classes, `${source}.${extension}`, content.slice(value.start, value.end));
35
+ }
36
+ for (const child of node.children || []) visitMarkup(child, source, content, classes, extension);
37
+ for (const branch of [
38
+ node.else,
39
+ node.pending,
40
+ node.then,
41
+ node.catch
42
+ ]) visitMarkup(branch, source, content, classes, extension);
43
+ }
44
+ async function loadSvelteCompiler() {
45
+ const specifier = ["svelte", "/compiler"].join("");
46
+ return await loadOptionalPeer(specifier, "Svelte");
47
+ }
48
+ async function extractSvelteClasses(source, content) {
49
+ if (!content.trim()) return [];
50
+ const compiler = await loadSvelteCompiler();
51
+ if (!compiler) throw new MasterCSSError({
52
+ code: "SOURCE_PARSE_ERROR",
53
+ domain: "tooling",
54
+ message: `Cannot parse ${source}: install the framework compiler or explicitly select kind: 'raw'.`
55
+ });
56
+ try {
57
+ const ast = compiler.parse(content);
58
+ const classes = /* @__PURE__ */ new Set();
59
+ const moduleExtension = scriptExtension(content, ast.module);
60
+ const instanceExtension = scriptExtension(content, ast.instance);
61
+ if (ast.module?.content) addOxc(classes, `${source}.${moduleExtension}`, content.slice(ast.module.content.start, ast.module.content.end));
62
+ if (ast.instance?.content) addOxc(classes, `${source}.${instanceExtension}`, content.slice(ast.instance.content.start, ast.instance.content.end));
63
+ visitMarkup(ast.html, source, content, classes, moduleExtension === "tsx" || instanceExtension === "tsx" ? "tsx" : moduleExtension === "ts" || instanceExtension === "ts" ? "ts" : "js");
64
+ return [...classes];
65
+ } catch (error) {
66
+ throw new MasterCSSError({
67
+ code: "SOURCE_PARSE_ERROR",
68
+ domain: "tooling",
69
+ message: `Cannot parse ${source}: ${String(error)}`
70
+ }, { cause: error });
71
+ }
72
+ }
73
+ function svelteAdapter() {
74
+ return {
75
+ name: "svelte",
76
+ test: isSvelteSource,
77
+ async extract({ source, content }) {
78
+ return await extractSvelteClasses(source, content);
79
+ }
80
+ };
81
+ }
82
+ export { SVELTE_SOURCE_EXT, extractSvelteClasses, svelteAdapter };
@@ -0,0 +1,11 @@
1
+ interface SourceAdapterInput {
2
+ source: string;
3
+ content: string;
4
+ }
5
+ interface SourceAdapter {
6
+ name: string;
7
+ test: RegExp | ((source: string) => boolean);
8
+ extract(input: SourceAdapterInput): Promise<string[]>;
9
+ }
10
+ declare function matchesSourceAdapter(adapter: SourceAdapter, source: string): boolean;
11
+ export { SourceAdapter, SourceAdapterInput, matchesSourceAdapter };
@@ -0,0 +1,9 @@
1
+ // src/source/adapters/types.ts
2
+ function matchesSourceAdapter(adapter, source) {
3
+ if (typeof adapter.test === "function") return adapter.test(source);
4
+ adapter.test.lastIndex = 0;
5
+ const matched = adapter.test.test(source);
6
+ adapter.test.lastIndex = 0;
7
+ return matched;
8
+ }
9
+ export { matchesSourceAdapter };
@@ -0,0 +1,5 @@
1
+ import { SourceAdapter } from "./types.js";
2
+ declare const VUE_SOURCE_EXT: RegExp;
3
+ declare function extractVueClasses(source: string, content: string): Promise<string[]>;
4
+ declare function vueAdapter(): SourceAdapter;
5
+ export { VUE_SOURCE_EXT, extractVueClasses, vueAdapter };
@@ -0,0 +1,50 @@
1
+ import { extractClassCandidatesNative } from "../native.js";
2
+ import { extractOxcClasses } from "./oxc.js";
3
+ import { loadOptionalPeer } from "./optional-peer.js";
4
+ import { MasterCSSError } from "@master/css-schema";
5
+ // src/source/adapters/vue.ts
6
+ const VUE_SOURCE_EXT = /\.vue(?:\?|$)/;
7
+ function isVueSource(source) {
8
+ return VUE_SOURCE_EXT.test(source) && !/[?&]type=style(?:&|$)/.test(source);
9
+ }
10
+ function add(classes, classNames) {
11
+ for (const className of classNames) if (className) classes.add(className);
12
+ }
13
+ async function loadVueCompiler() {
14
+ const specifier = ["vue", "/compiler-sfc"].join("");
15
+ return await loadOptionalPeer(specifier, "Vue SFC");
16
+ }
17
+ async function extractVueClasses(source, content) {
18
+ if (!content.trim()) return [];
19
+ const compiler = await loadVueCompiler();
20
+ if (!compiler) throw new MasterCSSError({
21
+ code: "SOURCE_PARSE_ERROR",
22
+ domain: "tooling",
23
+ message: `Cannot parse ${source}: install the framework compiler or explicitly select kind: 'raw'.`
24
+ });
25
+ try {
26
+ const classes = /* @__PURE__ */ new Set();
27
+ const { descriptor, errors } = compiler.parse(content, { filename: source });
28
+ if (errors.length) throw new Error(errors.map(String).join("; "));
29
+ if (descriptor.template?.content) add(classes, extractClassCandidatesNative(descriptor.template.content));
30
+ if (descriptor.script?.content) add(classes, extractOxcClasses(`${source}.${descriptor.script.lang || "js"}`, descriptor.script.content));
31
+ if (descriptor.scriptSetup?.content) add(classes, extractOxcClasses(`${source}.${descriptor.scriptSetup.lang || "js"}`, descriptor.scriptSetup.content));
32
+ return [...classes];
33
+ } catch (error) {
34
+ throw new MasterCSSError({
35
+ code: "SOURCE_PARSE_ERROR",
36
+ domain: "tooling",
37
+ message: `Cannot parse ${source}: ${String(error)}`
38
+ }, { cause: error });
39
+ }
40
+ }
41
+ function vueAdapter() {
42
+ return {
43
+ name: "vue",
44
+ test: isVueSource,
45
+ async extract({ source, content }) {
46
+ return await extractVueClasses(source, content);
47
+ }
48
+ };
49
+ }
50
+ export { VUE_SOURCE_EXT, extractVueClasses, vueAdapter };
@@ -0,0 +1,7 @@
1
+ import { SourceExtractor } from "./session.js";
2
+ import { MasterCSSWasmBindingLoadOptions } from "@master/css-binding/tooling";
3
+ type BrowserSourceExtractor = SourceExtractor & {
4
+ readonly binding: 'wasm';
5
+ };
6
+ declare function createSourceExtractor(options?: MasterCSSWasmBindingLoadOptions): Promise<BrowserSourceExtractor>;
7
+ export { BrowserSourceExtractor, type MasterCSSWasmBindingLoadOptions, createSourceExtractor };
@@ -0,0 +1,11 @@
1
+ import { bindSourceExtractor } from "./session.js";
2
+ import { createToolingBinding } from "@master/css-binding/tooling";
3
+ // src/source/browser.ts
4
+ async function createSourceExtractor(options = {}) {
5
+ const tooling = await createToolingBinding({
6
+ binding: "wasm",
7
+ wasm: options
8
+ });
9
+ return bindSourceExtractor(tooling.binding, await tooling.createSourceSession());
10
+ }
11
+ export { createSourceExtractor };
@@ -0,0 +1,35 @@
1
+ type MasterCSSSourceKind = 'auto' | 'raw' | 'oxc' | 'html' | 'astro' | 'markdown' | 'mdx';
2
+ /** Decoded HTML attribute text and indivisible UTF-16 source spans. */
3
+ interface MasterCSSDecodedHTMLAttribute {
4
+ readonly value: string;
5
+ readonly spans: readonly {
6
+ readonly range: {
7
+ readonly start: number;
8
+ readonly end: number;
9
+ };
10
+ readonly sourceRange: {
11
+ readonly start: number;
12
+ readonly end: number;
13
+ };
14
+ }[];
15
+ }
16
+ interface MasterCSSSourceExtractionInput {
17
+ readonly source: string;
18
+ readonly content: string;
19
+ readonly owner?: string;
20
+ readonly kind?: MasterCSSSourceKind;
21
+ }
22
+ interface MasterCSSSourceExtractionRequest {
23
+ readonly files: readonly MasterCSSSourceExtractionInput[];
24
+ }
25
+ interface MasterCSSExtractedSource {
26
+ readonly source: string;
27
+ readonly candidates: readonly string[];
28
+ readonly occurrences: readonly import('@master/css-binding/tooling').MasterCSSSourceOccurrence[];
29
+ readonly diagnostics: readonly import('@master/css-binding/tooling').MasterCSSDiagnostic[];
30
+ }
31
+ interface MasterCSSSourceExtraction {
32
+ readonly version: 2;
33
+ readonly files: readonly MasterCSSExtractedSource[];
34
+ }
35
+ export { MasterCSSDecodedHTMLAttribute, MasterCSSExtractedSource, MasterCSSSourceExtraction, MasterCSSSourceExtractionInput, MasterCSSSourceExtractionRequest, MasterCSSSourceKind };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { MasterCSSDecodedHTMLAttribute, MasterCSSExtractedSource, MasterCSSSourceExtraction, MasterCSSSourceExtractionInput, MasterCSSSourceExtractionRequest, MasterCSSSourceKind } from "./contracts.js";
2
+ import { MasterCSSBinding } from "@master/css-binding";
3
+ import { MasterCSSManifest } from "@master/css-schema/manifest";
4
+ declare function extractSource(request: MasterCSSSourceExtractionRequest, options: {
5
+ readonly manifest: MasterCSSManifest;
6
+ readonly binding?: MasterCSSBinding;
7
+ }): Promise<MasterCSSSourceExtraction>;
8
+ export { type MasterCSSDecodedHTMLAttribute, type MasterCSSExtractedSource, type MasterCSSSourceExtraction, type MasterCSSSourceExtractionInput, type MasterCSSSourceExtractionRequest, type MasterCSSSourceKind, extractSource };
@@ -0,0 +1,11 @@
1
+ import { createToolingSession } from "../tooling-session.js";
2
+ // src/source/index.ts
3
+ async function extractSource(request, options) {
4
+ const session = await createToolingSession(options);
5
+ try {
6
+ return session.extractSource(request);
7
+ } finally {
8
+ session.dispose();
9
+ }
10
+ }
11
+ export { extractSource };
@@ -0,0 +1,5 @@
1
+ declare function extractClassCandidatesNative(content: string): string[];
2
+ declare function extractOxcClassesNative(source: string, content: string): string[];
3
+ declare function extractHTMLClassesNative(source: string, content: string): string[];
4
+ declare function extractAstroClassesNative(source: string, content: string): string[];
5
+ export { extractAstroClassesNative, extractClassCandidatesNative, extractHTMLClassesNative, extractOxcClassesNative };
@@ -0,0 +1,53 @@
1
+ import { createToolingBindingSync } from "@master/css-binding/tooling/node";
2
+ import { MasterCSSError } from "@master/css-schema";
3
+ // src/source/native.ts
4
+ function binding() {
5
+ return createToolingBindingSync();
6
+ }
7
+ function extractClassCandidatesNative(content) {
8
+ return [...binding().extractClassCandidates(content)];
9
+ }
10
+ function extractOxcClassesNative(source, content) {
11
+ const session = binding().createSourceSession();
12
+ try {
13
+ const result = session.extract({ files: [{
14
+ source,
15
+ content,
16
+ kind: "oxc"
17
+ }] }).files[0];
18
+ if (result.diagnostics.length) {
19
+ const position = (offset) => {
20
+ const lines = content.slice(0, offset).split("\n");
21
+ return {
22
+ line: lines.length - 1,
23
+ character: lines.at(-1).length
24
+ };
25
+ };
26
+ throw new MasterCSSError({
27
+ code: "SOURCE_PARSE_ERROR",
28
+ domain: "tooling",
29
+ message: result.diagnostics[0].message,
30
+ diagnostics: result.diagnostics.map((diagnostic) => ({
31
+ ...diagnostic,
32
+ version: 2,
33
+ domain: "tooling",
34
+ severity: diagnostic.severity === "info" ? "information" : diagnostic.severity,
35
+ range: diagnostic.range ? {
36
+ start: position(diagnostic.range.start),
37
+ end: position(diagnostic.range.end)
38
+ } : void 0
39
+ }))
40
+ });
41
+ }
42
+ return [...result.candidates];
43
+ } finally {
44
+ session.dispose();
45
+ }
46
+ }
47
+ function extractHTMLClassesNative(source, content) {
48
+ return [...binding().extractHTMLClasses(source, content)];
49
+ }
50
+ function extractAstroClassesNative(source, content) {
51
+ return [...binding().extractAstroClasses(source, content)];
52
+ }
53
+ export { extractAstroClassesNative, extractClassCandidatesNative, extractHTMLClassesNative, extractOxcClassesNative };
@@ -0,0 +1,7 @@
1
+ import { MasterCSSSourceExtraction, MasterCSSSourceExtractionRequest } from "./contracts.js";
2
+ import "./index.js";
3
+ import { MasterCSSManifest } from "@master/css-schema/manifest";
4
+ declare function extractSourceSync(request: MasterCSSSourceExtractionRequest, options: {
5
+ readonly manifest: MasterCSSManifest;
6
+ }): MasterCSSSourceExtraction;
7
+ export { extractSourceSync };
@@ -0,0 +1,11 @@
1
+ import { createToolingSessionSync } from "../node.js";
2
+ // src/source/node.ts
3
+ function extractSourceSync(request, options) {
4
+ const session = createToolingSessionSync(options);
5
+ try {
6
+ return session.extractSource(request);
7
+ } finally {
8
+ session.dispose();
9
+ }
10
+ }
11
+ export { extractSourceSync };
@@ -0,0 +1,25 @@
1
+ import { MasterCSSSourceBatch, MasterCSSSourceBatchRequest, MasterCSSSourceExtractorKind } from "@master/css-binding/tooling";
2
+ type SourceBatchRequest = MasterCSSSourceBatchRequest;
3
+ type SourceExtractorKind = MasterCSSSourceExtractorKind;
4
+ interface SourceExtractor {
5
+ readonly binding: 'native' | 'wasm';
6
+ extract(request: SourceBatchRequest): MasterCSSSourceBatch;
7
+ extractClassCandidates(content: string): string[];
8
+ extractOxcClasses(source: string, content: string): string[];
9
+ extractHTMLClasses(source: string, content: string): string[];
10
+ extractAstroClasses(source: string, content: string): string[];
11
+ dispose(): void;
12
+ }
13
+ declare class SourceExtractorError extends Error {
14
+ readonly code: 'NATIVE_UNAVAILABLE' | 'SOURCE_BATCH_VERSION_MISMATCH';
15
+ constructor(code: 'NATIVE_UNAVAILABLE' | 'SOURCE_BATCH_VERSION_MISMATCH', message: string);
16
+ }
17
+ interface BindingSourceSession {
18
+ extract(request: unknown): unknown;
19
+ dispose(): void;
20
+ }
21
+ declare function bindSourceExtractor(binding: SourceExtractor['binding'], session: BindingSourceSession): SourceExtractor;
22
+ declare function createSourceExtractor(options?: {
23
+ readonly binding?: 'auto' | 'native' | 'wasm';
24
+ }): Promise<SourceExtractor>;
25
+ export { SourceBatchRequest, SourceExtractor, SourceExtractorError, SourceExtractorKind, bindSourceExtractor, createSourceExtractor };
@@ -0,0 +1,37 @@
1
+ import { MASTER_CSS_SOURCE_BATCH_VERSION, createToolingBinding } from "@master/css-binding/tooling";
2
+ // src/source/session.ts
3
+ var SourceExtractorError = class extends Error {
4
+ code;
5
+ constructor(code, message) {
6
+ super(message);
7
+ this.code = code;
8
+ this.name = "SourceExtractorError";
9
+ }
10
+ };
11
+ function parse(value) {
12
+ const result = value;
13
+ if (result.version !== MASTER_CSS_SOURCE_BATCH_VERSION) throw new SourceExtractorError("SOURCE_BATCH_VERSION_MISMATCH", `Expected Master CSS source batch version ${MASTER_CSS_SOURCE_BATCH_VERSION}, received ${String(result.version)}.`);
14
+ return result;
15
+ }
16
+ function bindSourceExtractor(binding, session) {
17
+ const extract = (request) => parse(session.extract(request));
18
+ const candidates = (source, content, kind) => extract({ files: [{
19
+ source,
20
+ content,
21
+ kind
22
+ }] }).files[0]?.candidates ?? [];
23
+ return {
24
+ binding,
25
+ extract,
26
+ extractClassCandidates: (content) => candidates("", content, "raw"),
27
+ extractOxcClasses: (source, content) => candidates(source, content, "oxc"),
28
+ extractHTMLClasses: (source, content) => candidates(source, content, "html"),
29
+ extractAstroClasses: (source, content) => candidates(source, content, "astro"),
30
+ dispose: () => session.dispose()
31
+ };
32
+ }
33
+ async function createSourceExtractor(options = {}) {
34
+ const tooling = await createToolingBinding({ binding: options.binding });
35
+ return bindSourceExtractor(tooling.binding, await tooling.createSourceSession());
36
+ }
37
+ export { SourceExtractorError, bindSourceExtractor, createSourceExtractor };