@geoql/doctor-core 1.4.1 → 1.6.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/dist/index.d.ts CHANGED
@@ -66,7 +66,8 @@ declare function scoreDiagnostics(diagnostics: Diagnostic[], config?: ScoreConfi
66
66
  //#endregion
67
67
  //#region src/types/project-info.d.ts
68
68
  type Framework = 'vue' | 'nuxt' | 'unknown';
69
- type Capability = string;
69
+ declare const CAPABILITIES: readonly ["vue:3", "vue:3.4", "vue:3.5", "vue:vapor", "nuxt:4", "nuxt:4.4", "nuxt4", "nuxt-config", "app-dir", "server-dir", "pages-dir", "wrangler", "auto-imports:vue", "components:auto", "pinia", "vue-router", "typescript", "typescript:6", "monorepo:pnpm", "monorepo:yarn", "monorepo:npm", "cf-pages:enabled", "nitro:node-server"];
70
+ type Capability = (typeof CAPABILITIES)[number];
70
71
  type MonorepoKind = 'pnpm' | 'yarn' | 'npm' | 'turbo' | null;
71
72
  interface ProjectInfo {
72
73
  readonly framework: Framework;
@@ -464,10 +465,12 @@ interface DirectiveSet {
464
465
  declare function parseDirectives(text: string): DirectiveSet;
465
466
  //#endregion
466
467
  //#region src/git-scope.d.ts
467
- type GitScopeMode = 'diff' | 'staged';
468
+ type GitScopeMode = 'diff' | 'staged' | 'changed-from';
468
469
  interface GitScopeOptions {
469
470
  rootDir: string;
470
471
  mode: GitScopeMode;
472
+ ref?: string;
473
+ includeUntracked?: boolean;
471
474
  }
472
475
  declare function listChangedFiles(options: GitScopeOptions): Promise<string[]>;
473
476
  //#endregion
package/dist/index.js CHANGED
@@ -1582,7 +1582,8 @@ const VUE_DEFAULT_RULES = {
1582
1582
  "vue-doctor/security/no-inner-html": "error",
1583
1583
  "vue-doctor/security/no-eval-like": "error",
1584
1584
  "vue-doctor/security/no-auth-token-in-web-storage": "warn",
1585
- "vue-doctor/security/no-secrets-in-source": "warn"
1585
+ "vue-doctor/security/no-secrets-in-source": "warn",
1586
+ "vue-doctor/security/markdown-it-unsanitized-html": "warn"
1586
1587
  };
1587
1588
  const NUXT_PLUGIN_RULES = {
1588
1589
  "nuxt-doctor/ai-slop/no-process-client-server": "error",
@@ -1595,6 +1596,7 @@ const NUXT_PLUGIN_RULES = {
1595
1596
  "nuxt-doctor/server-routes/createError-on-failure": "warn",
1596
1597
  "nuxt-doctor/hydration/no-document-in-setup": "error",
1597
1598
  "nuxt-doctor/hydration/clientOnly-for-browser-apis": "error",
1599
+ "nuxt-doctor/hydration/no-browser-global-in-computed": "error",
1598
1600
  "nuxt-doctor/security/no-user-input-in-fetch-url": "warn"
1599
1601
  };
1600
1602
  const VUE_OXLINT_RULE_IDS = /* @__PURE__ */ new Set([
@@ -1630,9 +1632,12 @@ const VUE_OXLINT_RULE_IDS = /* @__PURE__ */ new Set([
1630
1632
  "vue-doctor/reactivity/prefer-shallowRef-for-large-data",
1631
1633
  "vue-doctor/reactivity/prefer-readonly-for-injected",
1632
1634
  "vue-doctor/reactivity/no-fresh-deps-in-watch",
1635
+ "vue-doctor/reactivity/no-stale-timer-ref",
1636
+ "vue-doctor/reactivity/effect-listener-cleanup-mismatch",
1633
1637
  "vue-doctor/composition/prefer-script-setup-for-new-files",
1634
1638
  "vue-doctor/composition/defineProps-typed",
1635
1639
  "vue-doctor/composition/no-pinia-store-in-setup",
1640
+ "vue-doctor/composition/no-prop-callback-in-setup",
1636
1641
  "vue-doctor/performance/prefer-defineAsyncComponent-on-route",
1637
1642
  "vue-doctor/performance/prefer-module-scope-static-value",
1638
1643
  "vue-doctor/performance/prefer-module-scope-pure-function",
@@ -1640,7 +1645,8 @@ const VUE_OXLINT_RULE_IDS = /* @__PURE__ */ new Set([
1640
1645
  "vue-doctor/security/no-inner-html",
1641
1646
  "vue-doctor/security/no-eval-like",
1642
1647
  "vue-doctor/security/no-auth-token-in-web-storage",
1643
- "vue-doctor/security/no-secrets-in-source"
1648
+ "vue-doctor/security/no-secrets-in-source",
1649
+ "vue-doctor/security/markdown-it-unsanitized-html"
1644
1650
  ]);
1645
1651
  const NUXT_OXLINT_RULE_IDS = new Set(Object.keys(NUXT_PLUGIN_RULES));
1646
1652
  function oxlintRuleAllowlist(framework) {
@@ -2162,6 +2168,20 @@ const RULE_REGISTRY = [
2162
2168
  source: "doctor",
2163
2169
  recommended: true
2164
2170
  },
2171
+ {
2172
+ id: "vue-doctor/reactivity/no-stale-timer-ref",
2173
+ severity: "warn",
2174
+ category: "reactivity",
2175
+ source: "doctor",
2176
+ recommended: true
2177
+ },
2178
+ {
2179
+ id: "vue-doctor/reactivity/effect-listener-cleanup-mismatch",
2180
+ severity: "warn",
2181
+ category: "reactivity",
2182
+ source: "doctor",
2183
+ recommended: true
2184
+ },
2165
2185
  {
2166
2186
  id: "vue-doctor/composition/prefer-script-setup-for-new-files",
2167
2187
  severity: "warn",
@@ -2183,6 +2203,13 @@ const RULE_REGISTRY = [
2183
2203
  source: "doctor",
2184
2204
  recommended: true
2185
2205
  },
2206
+ {
2207
+ id: "vue-doctor/composition/no-prop-callback-in-setup",
2208
+ severity: "warn",
2209
+ category: "composition",
2210
+ source: "doctor",
2211
+ recommended: true
2212
+ },
2186
2213
  {
2187
2214
  id: "vue-doctor/performance/prefer-defineAsyncComponent-on-route",
2188
2215
  severity: "info",
@@ -2540,6 +2567,13 @@ const RULE_REGISTRY = [
2540
2567
  source: "doctor",
2541
2568
  recommended: true
2542
2569
  },
2570
+ {
2571
+ id: "nuxt-doctor/hydration/no-browser-global-in-computed",
2572
+ severity: "error",
2573
+ category: "hydration",
2574
+ source: "doctor",
2575
+ recommended: true
2576
+ },
2543
2577
  {
2544
2578
  id: "nuxt-doctor/hydration/clientOnly-for-browser-apis",
2545
2579
  severity: "error",
@@ -2582,6 +2616,13 @@ const RULE_REGISTRY = [
2582
2616
  source: "doctor",
2583
2617
  recommended: true
2584
2618
  },
2619
+ {
2620
+ id: "vue-doctor/security/markdown-it-unsanitized-html",
2621
+ severity: "warn",
2622
+ category: "security",
2623
+ source: "doctor",
2624
+ recommended: true
2625
+ },
2585
2626
  {
2586
2627
  id: "vue-doctor/security/no-target-blank-without-rel",
2587
2628
  severity: "warn",
@@ -4926,32 +4967,68 @@ const SOURCE_EXTENSIONS = [
4926
4967
  function isSourceFile(path) {
4927
4968
  return SOURCE_EXTENSIONS.some((ext) => path.endsWith(ext));
4928
4969
  }
4970
+ var GitRefError = class extends Error {
4971
+ ref;
4972
+ constructor(ref) {
4973
+ super(`Cannot resolve git ref "${ref}" for --changed-files-from`);
4974
+ this.ref = ref;
4975
+ this.name = "GitRefError";
4976
+ }
4977
+ };
4929
4978
  async function gitLines(rootDir, args) {
4930
4979
  const { stdout } = await execFileAsync("git", args, { cwd: rootDir });
4931
4980
  return stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
4932
4981
  }
4933
- async function listChangedFiles(options) {
4934
- const { rootDir, mode } = options;
4935
- let relPaths;
4936
- if (mode === "staged") relPaths = await gitLines(rootDir, [
4937
- "diff",
4938
- "--name-only",
4939
- "--cached",
4940
- "--diff-filter=ACMR"
4982
+ async function untrackedLines(rootDir) {
4983
+ return gitLines(rootDir, [
4984
+ "ls-files",
4985
+ "--others",
4986
+ "--exclude-standard"
4941
4987
  ]);
4942
- else {
4943
- const tracked = await gitLines(rootDir, [
4988
+ }
4989
+ async function resolveRef(rootDir, ref) {
4990
+ try {
4991
+ await execFileAsync("git", [
4992
+ "rev-parse",
4993
+ "--verify",
4994
+ `${ref}^{commit}`
4995
+ ], { cwd: rootDir });
4996
+ } catch {
4997
+ throw new GitRefError(ref);
4998
+ }
4999
+ }
5000
+ async function listChangedFiles(options) {
5001
+ const { rootDir, mode, ref, includeUntracked } = options;
5002
+ const relPaths = [];
5003
+ if (mode === "staged") {
5004
+ relPaths.push(...await gitLines(rootDir, [
5005
+ "diff",
5006
+ "--name-only",
5007
+ "--cached",
5008
+ "--relative",
5009
+ "--diff-filter=ACMR"
5010
+ ]));
5011
+ if (includeUntracked) relPaths.push(...await untrackedLines(rootDir));
5012
+ } else if (mode === "changed-from") {
5013
+ const base = ref ?? "HEAD";
5014
+ await resolveRef(rootDir, base);
5015
+ relPaths.push(...await gitLines(rootDir, [
5016
+ "diff",
5017
+ "--name-only",
5018
+ base,
5019
+ "--relative",
5020
+ "--diff-filter=ACMR"
5021
+ ]));
5022
+ if (includeUntracked) relPaths.push(...await untrackedLines(rootDir));
5023
+ } else {
5024
+ relPaths.push(...await gitLines(rootDir, [
4944
5025
  "diff",
4945
5026
  "--name-only",
4946
5027
  "HEAD",
5028
+ "--relative",
4947
5029
  "--diff-filter=ACMR"
4948
- ]);
4949
- const untracked = await gitLines(rootDir, [
4950
- "ls-files",
4951
- "--others",
4952
- "--exclude-standard"
4953
- ]);
4954
- relPaths = [...tracked, ...untracked];
5030
+ ]));
5031
+ relPaths.push(...await untrackedLines(rootDir));
4955
5032
  }
4956
5033
  const absolute = relPaths.filter(isSourceFile).map((rel) => resolve(rootDir, rel));
4957
5034
  return [...new Set(absolute)].sort();