@rafters/veneer 0.0.2 → 0.0.3

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/dist/bin.mjs CHANGED
@@ -1,20 +1,54 @@
1
1
  #!/usr/bin/env node
2
- import { t as check } from "./check-DxTxqBre.mjs";
2
+ import { i as relativeFile } from "./lint-Tvq5uHHS.mjs";
3
+ import { t as check } from "./check-CbVCXbX6.mjs";
4
+ import path from "node:path";
5
+ import { existsSync, realpathSync } from "node:fs";
6
+ import { parseArgs } from "node:util";
7
+ import { text } from "node:stream/consumers";
3
8
  //#region src/bin.ts
4
- const [root, ...rest] = process.argv.slice(2);
5
- if (root?.startsWith("-") || rest.length > 0) {
6
- process.stderr.write("usage: rafters-check [root]\n");
7
- process.exitCode = 1;
8
- } else {
9
- const result = await check(root ?? process.cwd());
10
- if (result.ok) {
11
- process.stdout.write(result.report);
12
- for (const { message } of result.notices) process.stderr.write(`${message}\n`);
13
- process.exitCode = result.diagnostics.some(({ severity }) => severity === "error") ? 1 : 0;
14
- } else {
9
+ const COULD_NOT_RUN = 2;
10
+ function parsedArguments() {
11
+ try {
12
+ const { values, positionals } = parseArgs({
13
+ allowPositionals: true,
14
+ options: { stdin: { type: "string" } }
15
+ });
16
+ const [root, ...rest] = positionals;
17
+ return rest.length > 0 ? void 0 : {
18
+ root,
19
+ stdinPath: values.stdin
20
+ };
21
+ } catch {
22
+ return;
23
+ }
24
+ }
25
+ function resolvedLinks(file) {
26
+ if (existsSync(file)) return realpathSync(file);
27
+ const parent = path.dirname(file);
28
+ return parent === file ? file : path.join(resolvedLinks(parent), path.basename(file));
29
+ }
30
+ async function run(root, stdinPath) {
31
+ const file = stdinPath && relativeFile(resolvedLinks(root), resolvedLinks(path.resolve(stdinPath)));
32
+ const unsaved = file === void 0 ? void 0 : { [file]: await text(process.stdin) };
33
+ const result = await check(root, { unsaved });
34
+ if (!result.ok) {
15
35
  for (const { message } of result.errors) process.stderr.write(`${message}\n`);
16
- process.exitCode = 1;
36
+ return COULD_NOT_RUN;
17
37
  }
38
+ process.stdout.write(result.report);
39
+ for (const { message } of result.notices) process.stderr.write(`${message}\n`);
40
+ return result.diagnostics.some(({ severity }) => severity === "error") ? 1 : 0;
41
+ }
42
+ const parsed = parsedArguments();
43
+ if (parsed) try {
44
+ process.exitCode = await run(parsed.root ?? process.cwd(), parsed.stdinPath);
45
+ } catch (error) {
46
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
47
+ process.exitCode = COULD_NOT_RUN;
48
+ }
49
+ else {
50
+ process.stderr.write("usage: rafters-check [root] [--stdin <path>]\n");
51
+ process.exitCode = COULD_NOT_RUN;
18
52
  }
19
53
  //#endregion
20
54
  export {};
@@ -1,4 +1,4 @@
1
- import { a as ProjectError, i as resolveComponents, n as report, o as openProject, r as compareCodePoints, s as readConfig, t as lint } from "./lint-BabXVYQJ.mjs";
1
+ import { a as resolveComponents, c as readConfig, n as report, o as ProjectError, r as compareCodePoints, s as openProject, t as lint } from "./lint-Tvq5uHHS.mjs";
2
2
  import path from "node:path";
3
3
  import { mkdir, rename, rm, writeFile } from "node:fs/promises";
4
4
  import { lstatSync } from "node:fs";
@@ -139,6 +139,7 @@ async function check(projectRoot, options = {}) {
139
139
  const asked = options.paths ?? (unsavedFiles.length > 0 ? unsavedFiles : void 0);
140
140
  const diagnostics = await lint(project, {
141
141
  componentFolders: config.componentFolders,
142
+ scan: config.scan,
142
143
  files: isSave ? void 0 : asked?.filter((file) => !outside.includes(file))
143
144
  });
144
145
  const written = isSave ? await writeDocsFrom(project, config) : void 0;
package/dist/index.d.mts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { AstroCheck, Diagnostic as Diagnostic$1 } from "@astrojs/language-server";
2
2
  import * as TypeScript from "typescript";
3
3
  //#region src/config.d.ts
4
+ declare const SCANS: readonly ["system", "format", "all"];
5
+ type Scan = (typeof SCANS)[number];
4
6
  interface Notice {
5
7
  code: string;
6
8
  message: string;
@@ -47,6 +49,7 @@ interface LintDiagnostic extends Diagnostic {
47
49
  }
48
50
  export declare function lint(project: Project, options: {
49
51
  componentFolders: string[];
52
+ scan?: Scan;
50
53
  files?: string[];
51
54
  }): Promise<LintDiagnostic[]>;
52
55
  export declare function report(diagnostics: LintDiagnostic[]): string;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { a as ProjectError, n as report, o as openProject, t as lint } from "./lint-BabXVYQJ.mjs";
2
- import { n as writeDocs, t as check } from "./check-DxTxqBre.mjs";
1
+ import { n as report, o as ProjectError, s as openProject, t as lint } from "./lint-Tvq5uHHS.mjs";
2
+ import { n as writeDocs, t as check } from "./check-CbVCXbX6.mjs";
3
3
  export { ProjectError, check, lint, openProject, report, writeDocs };
@@ -6,6 +6,12 @@ import { format } from "node:util";
6
6
  import { AstroCheck } from "@astrojs/language-server";
7
7
  //#region src/config.ts
8
8
  const CONFIG_FILE = ".rafters/config.rafters.json";
9
+ const SCANS = [
10
+ "system",
11
+ "format",
12
+ "all"
13
+ ];
14
+ const isScan = (value) => SCANS.some((scan) => scan === value);
9
15
  function isObject(value) {
10
16
  return typeof value === "object" && value !== null && !Array.isArray(value);
11
17
  }
@@ -98,7 +104,10 @@ async function readConfig(root) {
98
104
  }
99
105
  if (intent !== void 0 && typeof intent !== "string") errors.push(fieldError("intent", "expected a string", intent));
100
106
  if (veneer !== void 0 && !isObject(veneer)) errors.push(fieldError("veneer", "expected an object", veneer));
101
- else if (veneer?.mdxPath !== void 0 && typeof veneer.mdxPath !== "string") errors.push(fieldError("veneer.mdxPath", "expected a string", veneer.mdxPath));
107
+ else {
108
+ if (veneer?.mdxPath !== void 0 && typeof veneer.mdxPath !== "string") errors.push(fieldError("veneer.mdxPath", "expected a string", veneer.mdxPath));
109
+ if (veneer?.scan !== void 0 && !isScan(veneer.scan)) errors.push(fieldError("veneer.scan", `expected one of ${SCANS.join(", ")}`, veneer.scan));
110
+ }
102
111
  if (errors.length > 0) return {
103
112
  ok: false,
104
113
  errors
@@ -107,6 +116,7 @@ async function readConfig(root) {
107
116
  ok: true,
108
117
  intent: typeof intent === "string" ? intent : null,
109
118
  componentFolders,
119
+ scan: isObject(veneer) && isScan(veneer.scan) ? veneer.scan : "format",
110
120
  notices
111
121
  };
112
122
  }
@@ -669,7 +679,15 @@ function ownPropNames(reader, component, sourceFile) {
669
679
  if (!signature) return [];
670
680
  return propsOfSignature(reader, signature, sourceFile, /* @__PURE__ */ new Map()).props.map(({ name }) => name);
671
681
  }
672
- function intelligenceBlock(reader, sourceFile) {
682
+ const INTELLIGENCE_TAGS = [
683
+ "cognitive-load",
684
+ "attention-economics",
685
+ "trust-building",
686
+ "accessibility",
687
+ "semantic-meaning",
688
+ "usage-patterns"
689
+ ];
690
+ function placedBlocks(reader, sourceFile) {
673
691
  const { ts } = reader;
674
692
  const blocks = [];
675
693
  const visit = (node) => {
@@ -684,7 +702,16 @@ function intelligenceBlock(reader, sourceFile) {
684
702
  block,
685
703
  at
686
704
  }];
687
- }).sort((a, b) => a.at - b.at)[0]?.block;
705
+ });
706
+ }
707
+ function intelligenceBlock(reader, sourceFile) {
708
+ return placedBlocks(reader, sourceFile).sort((a, b) => a.at - b.at)[0]?.block;
709
+ }
710
+ function holdsAllIntelligenceTags(reader, sourceFile) {
711
+ return placedBlocks(reader, sourceFile).some(({ block }) => {
712
+ const names = new Set(block.tags?.map((tag) => tag.tagName.text));
713
+ return INTELLIGENCE_TAGS.every((tag) => names.has(tag));
714
+ });
688
715
  }
689
716
  function intelligence(reader, sourceFile) {
690
717
  const { ts } = reader;
@@ -785,6 +812,12 @@ const CLASS_ATTRIBUTES = /* @__PURE__ */ new Set([
785
812
  ]);
786
813
  const MAX_RESOLVE_STEPS = 8;
787
814
  const realPath = (file) => existsSync(file) ? realpathSync(file) : file;
815
+ function qualifies(reader, sourceFile) {
816
+ const { fileName } = sourceFile;
817
+ const stem = fileName.replace(/\.(tsx|astro)$/, "");
818
+ const { sys } = reader.ts;
819
+ return stem !== fileName && sys.fileExists(`${stem}.behavior.ts`) && sys.fileExists(`${stem}.classes.ts`) && holdsAllIntelligenceTags(reader, sourceFile);
820
+ }
788
821
  function offsetAt(text, line, column) {
789
822
  const breaks = /\r\n|\r|\n/g;
790
823
  let start = 0;
@@ -817,8 +850,8 @@ function elementUsing(ts, node) {
817
850
  const element = tag.parent;
818
851
  return ts.isJsxOpeningLikeElement(element) && element.tagName === tag ? element : void 0;
819
852
  }
820
- function resolveTag({ ts, tc }, { tagName }) {
821
- let symbol = tc.getSymbolAtLocation(ts.isPropertyAccessExpression(tagName) ? tagName.name : tagName);
853
+ function resolveSymbol({ ts, tc }, start) {
854
+ let symbol = start;
822
855
  for (let step = 0; symbol && step < MAX_RESOLVE_STEPS; step += 1) {
823
856
  const declaration = symbol.valueDeclaration;
824
857
  if (symbol.flags & ts.SymbolFlags.Alias) symbol = tc.getAliasedSymbol(symbol);
@@ -826,6 +859,10 @@ function resolveTag({ ts, tc }, { tagName }) {
826
859
  else return symbol;
827
860
  }
828
861
  }
862
+ function resolveTag(reader, { tagName }) {
863
+ const { ts, tc } = reader;
864
+ return resolveSymbol(reader, tc.getSymbolAtLocation(ts.isPropertyAccessExpression(tagName) ? tagName.name : tagName));
865
+ }
829
866
  function deprecatedText({ ts, tc }, element, name) {
830
867
  const parameter = tc.getResolvedSignature(element)?.parameters[0];
831
868
  const tag = (parameter && tc.getTypeOfSymbol(parameter).getProperty(name))?.getJsDocTags(tc).find((found) => found.name === "deprecated");
@@ -842,46 +879,60 @@ function utilityOf(className) {
842
879
  }
843
880
  return className.slice(start);
844
881
  }
845
- function classLiterals(ts, node) {
846
- if (ts.isStringLiteralLike(node)) return [node];
847
- if (ts.isJsxExpression(node) || ts.isParenthesizedExpression(node)) return node.expression ? classLiterals(ts, node.expression) : [];
848
- if (ts.isArrayLiteralExpression(node)) return node.elements.flatMap((element) => classLiterals(ts, element));
849
- if (ts.isObjectLiteralExpression(node)) return node.properties.flatMap((property) => ts.isPropertyAssignment(property) && ts.isStringLiteral(property.name) ? [property.name] : []);
850
- return [];
882
+ function constString(reader, identifier) {
883
+ const { ts, tc } = reader;
884
+ const declaration = resolveSymbol(reader, tc.getSymbolAtLocation(identifier))?.valueDeclaration;
885
+ if (!declaration || !ts.isVariableDeclaration(declaration) || !(ts.getCombinedNodeFlags(declaration) & ts.NodeFlags.Const) || !declaration.initializer) return;
886
+ return ts.isStringLiteralLike(declaration.initializer) ? declaration.initializer : void 0;
887
+ }
888
+ function collectClassStrings(reader, sourceFile, isOwnSource, node, found) {
889
+ const { ts } = reader;
890
+ if (ts.isStringLiteralLike(node)) found.set(node, node);
891
+ else if (ts.isIdentifier(node)) {
892
+ const literal = constString(reader, node);
893
+ const declaredIn = literal?.getSourceFile();
894
+ if (!literal || !declaredIn) return;
895
+ if (declaredIn === sourceFile) found.set(literal, literal);
896
+ else if (isOwnSource(declaredIn.fileName)) found.set(node, literal);
897
+ } else ts.forEachChild(node, (child) => {
898
+ collectClassStrings(reader, sourceFile, isOwnSource, child, found);
899
+ });
851
900
  }
852
- function bracketsInLiteral(reader, file, sourceFile, literal) {
853
- return [...literal.getText(sourceFile).slice(1, -1).matchAll(/\S+/g)].flatMap((match) => {
901
+ function bracketsInLiteral(reader, file, sourceFile, at, literal) {
902
+ return [...literal.getText(literal.getSourceFile()).slice(1, -1).matchAll(/\S+/g)].flatMap((match) => {
854
903
  const [className] = match;
855
904
  if (!utilityOf(className).includes("[")) return [];
856
- const position = positionOf(reader, sourceFile, literal.getStart(sourceFile) + 1 + match.index);
905
+ const inLiteral = at === literal;
906
+ const position = positionOf(reader, sourceFile, at.getStart(sourceFile) + (inLiteral ? 1 + match.index : 0));
857
907
  if (!position) return [];
858
908
  return [{
859
909
  file,
860
910
  line: position.line,
861
911
  column: position.column,
862
912
  endLine: position.line,
863
- endColumn: position.column + className.length,
913
+ endColumn: position.column + (inLiteral ? className.length : at.getWidth(sourceFile)),
864
914
  severity: "error",
865
915
  code: "rafters(arbitrary-value)",
866
916
  message: `${className} is an arbitrary value`
867
917
  }];
868
918
  });
869
919
  }
870
- function bracketValues(reader, file, sourceFile) {
920
+ function bracketValues(reader, file, sourceFile, isOwnSource) {
871
921
  const { ts } = reader;
872
- const found = [];
922
+ const strings = /* @__PURE__ */ new Map();
873
923
  const visit = (node) => {
874
924
  if (ts.isJsxAttribute(node) && node.initializer) {
875
925
  const { name } = node;
876
926
  const attribute = ts.isJsxNamespacedName(name) ? `${name.namespace.text}:${name.name.text}` : name.text;
877
- if (CLASS_ATTRIBUTES.has(attribute)) for (const literal of classLiterals(ts, node.initializer)) found.push(...bracketsInLiteral(reader, file, sourceFile, literal));
878
- }
927
+ if (CLASS_ATTRIBUTES.has(attribute)) collectClassStrings(reader, sourceFile, isOwnSource, node.initializer, strings);
928
+ } else if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "classy") for (const argument of node.arguments) collectClassStrings(reader, sourceFile, isOwnSource, argument, strings);
879
929
  ts.forEachChild(node, visit);
880
930
  };
881
931
  visit(sourceFile);
882
- return found;
932
+ return [...strings].flatMap(([at, literal]) => bracketsInLiteral(reader, file, sourceFile, at, literal));
883
933
  }
884
934
  const FILL_WORD = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
935
+ const FILL_TOKEN = /^bg-fill-[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
885
936
  const FILL_ALPHA = /^(100|[1-9]?[0-9])$/;
886
937
  const AUTHORED_FILL = "a fill the designer authors, fill=\"bg-fill-<name>\"";
887
938
  const isFillStop = (stop) => {
@@ -901,17 +952,17 @@ async function loadSurfaces(root) {
901
952
  return { failure: error instanceof Error ? error.message : String(error) };
902
953
  }
903
954
  }
904
- function fillLiteral(ts, node) {
955
+ function valueLiteral(ts, node) {
905
956
  const { initializer } = node;
906
957
  if (!initializer) return void 0;
907
958
  if (ts.isStringLiteral(initializer)) return initializer;
908
959
  const inner = ts.isJsxExpression(initializer) ? initializer.expression : void 0;
909
960
  return inner && ts.isStringLiteralLike(inner) ? inner : void 0;
910
961
  }
911
- function fillAttributes({ ts }, sourceFile) {
962
+ function valueAttributes({ ts }, sourceFile) {
912
963
  const found = [];
913
964
  const visit = (node) => {
914
- if (ts.isJsxAttribute(node) && ts.isIdentifier(node.name) && node.name.text === "fill") found.push(node);
965
+ if (ts.isJsxAttribute(node) && ts.isIdentifier(node.name) && (node.name.text === "fill" || node.name.text === "surface")) found.push(node);
915
966
  ts.forEachChild(node, visit);
916
967
  };
917
968
  visit(sourceFile);
@@ -933,6 +984,17 @@ async function lint(project, options) {
933
984
  const real = realPath(file);
934
985
  return folders.some((folder) => real.startsWith(folder));
935
986
  };
987
+ const scan = options.scan ?? "format";
988
+ const projectRoot = realPath(project.root);
989
+ const isOwnSource = (file) => {
990
+ const [first, ...rest] = path.relative(projectRoot, realPath(file)).split(path.sep);
991
+ return first !== ".." && first !== "node_modules" && !rest.includes("node_modules");
992
+ };
993
+ const isExempt = (sourceFile) => isUnderFolder(sourceFile.fileName) || qualifies(reader, sourceFile);
994
+ const isCheckedUse = (declaredIn) => {
995
+ if (scan === "system") return isUnderFolder(declaredIn.fileName);
996
+ return isExempt(declaredIn) || scan === "all" && isOwnSource(declaredIn.fileName);
997
+ };
936
998
  const propsHelp = /* @__PURE__ */ new Map();
937
999
  const reportedUse = (sourceFile, diagnostic) => {
938
1000
  const offset = programOffset(reader, sourceFile, diagnostic);
@@ -943,7 +1005,7 @@ async function lint(project, options) {
943
1005
  const declaration = component?.valueDeclaration ?? component?.declarations?.[0];
944
1006
  if (!element || !component || !declaration) return void 0;
945
1007
  const declaredIn = declaration.getSourceFile();
946
- if (!isUnderFolder(declaredIn.fileName)) return void 0;
1008
+ if (!isCheckedUse(declaredIn)) return void 0;
947
1009
  let help;
948
1010
  if (diagnostic.code === "ts(6385)") help = deprecatedText(reader, element, node.getText(sourceFile));
949
1011
  else {
@@ -966,15 +1028,44 @@ async function lint(project, options) {
966
1028
  if ("failure" in loaded) return `the project's tokens could not be loaded, so no replacement is named: ${loaded.failure}`;
967
1029
  return loaded.words.has(value) ? `surface="${value}"` : AUTHORED_FILL;
968
1030
  };
969
- const retiredFills = async (file, sourceFile) => {
1031
+ const fillFinding = async (value) => {
1032
+ if (value === "" || FILL_TOKEN.test(value)) return void 0;
1033
+ const form = retiredFillForm(value);
1034
+ if (!form) return {
1035
+ code: "rafters(invalid-fill)",
1036
+ message: `fill="${value}" is not exactly one bg-fill-* token`
1037
+ };
1038
+ return {
1039
+ code: "rafters(retired-fill)",
1040
+ message: `fill="${value}" is a retired fill value`,
1041
+ help: await replacement(value, form)
1042
+ };
1043
+ };
1044
+ const surfaceFinding = async (value) => {
1045
+ if (value === "") return void 0;
1046
+ surfaces ??= loadSurfaces(project.root);
1047
+ const loaded = await surfaces;
1048
+ if ("failure" in loaded) return {
1049
+ code: "rafters(unknown-surface)",
1050
+ message: `surface="${value}" could not be checked`,
1051
+ help: `the project's tokens could not be loaded, so no surface is named: ${loaded.failure}`
1052
+ };
1053
+ if (loaded.words.has(value)) return void 0;
1054
+ return {
1055
+ code: "rafters(unknown-surface)",
1056
+ message: `surface="${value}" is not a surface in the project's tokens`
1057
+ };
1058
+ };
1059
+ const badValues = async (file, sourceFile) => {
970
1060
  const flagged = [];
971
- for (const attribute of fillAttributes(reader, sourceFile)) {
972
- const literal = fillLiteral(ts, attribute);
973
- const form = literal && retiredFillForm(literal.text);
974
- if (!literal || !form) continue;
1061
+ for (const attribute of valueAttributes(reader, sourceFile)) {
1062
+ const literal = valueLiteral(ts, attribute);
1063
+ if (!literal) continue;
975
1064
  const component = resolveTag(reader, attribute.parent.parent);
976
1065
  const declaration = component?.valueDeclaration ?? component?.declarations?.[0];
977
- if (!declaration || !isUnderFolder(declaration.getSourceFile().fileName)) continue;
1066
+ if (!declaration || !isCheckedUse(declaration.getSourceFile())) continue;
1067
+ const finding = await (attribute.name.getText(sourceFile) === "fill" ? fillFinding(literal.text) : surfaceFinding(literal.text));
1068
+ if (!finding) continue;
978
1069
  const start = positionOf(reader, sourceFile, attribute.getStart(sourceFile));
979
1070
  const end = positionOf(reader, sourceFile, attribute.end);
980
1071
  if (!start || !end) continue;
@@ -985,9 +1076,7 @@ async function lint(project, options) {
985
1076
  endLine: end.line,
986
1077
  endColumn: end.column,
987
1078
  severity: "error",
988
- code: "rafters(retired-fill)",
989
- message: `fill="${literal.text}" is a retired fill value`,
990
- help: await replacement(literal.text, form)
1079
+ ...finding
991
1080
  });
992
1081
  }
993
1082
  return flagged;
@@ -1001,9 +1090,9 @@ async function lint(project, options) {
1001
1090
  const reported = reportedUse(sourceFile, diagnostic);
1002
1091
  if (reported) found.push(reported);
1003
1092
  }
1004
- if (!isUnderFolder(absolute)) {
1005
- found.push(...bracketValues(reader, file, sourceFile));
1006
- found.push(...await retiredFills(file, sourceFile));
1093
+ if (!isExempt(sourceFile)) {
1094
+ found.push(...bracketValues(reader, file, sourceFile, isOwnSource));
1095
+ found.push(...await badValues(file, sourceFile));
1007
1096
  }
1008
1097
  }
1009
1098
  return found.sort((a, b) => compareCodePoints(a.file, b.file) || a.line - b.line || a.column - b.column);
@@ -1021,4 +1110,4 @@ function report(diagnostics) {
1021
1110
  return lines.map((line) => `${line}\n`).join("");
1022
1111
  }
1023
1112
  //#endregion
1024
- export { ProjectError as a, resolveComponents as i, report as n, openProject as o, compareCodePoints as r, readConfig as s, lint as t };
1113
+ export { resolveComponents as a, readConfig as c, relativeFile as i, report as n, ProjectError as o, compareCodePoints as r, openProject as s, lint as t };
package/dist/worker.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { o as openProject, s as readConfig, t as lint } from "./lint-BabXVYQJ.mjs";
1
+ import { c as readConfig, s as openProject, t as lint } from "./lint-Tvq5uHHS.mjs";
2
2
  import path from "node:path";
3
3
  import { existsSync } from "node:fs";
4
4
  import { promisify } from "node:util";
@@ -30,7 +30,7 @@ process.stdout.write(JSON.stringify(await check(${JSON.stringify(root)}, { save:
30
30
  async function serve(root) {
31
31
  const config = await readConfig(root);
32
32
  if (!config.ok) throw new Error(messages(config.errors));
33
- const { componentFolders } = config;
33
+ const { componentFolders, scan } = config;
34
34
  let project = await openProject(root);
35
35
  const unsaved = /* @__PURE__ */ new Map();
36
36
  const outside = /* @__PURE__ */ new Set();
@@ -57,6 +57,7 @@ async function serve(root) {
57
57
  }
58
58
  return lint(project, {
59
59
  componentFolders,
60
+ scan,
60
61
  files: [file]
61
62
  });
62
63
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rafters/veneer",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Docs, rafters check and the composite compile for rafters projects",
5
5
  "license": "MIT",
6
6
  "repository": {