Thomas G. Lopes commited on
Commit
7357f85
·
1 Parent(s): 0a59c60

custom rule

Browse files
eslint-rules/enforce-extensions.js ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fs from "fs";
2
+ import path from "path";
3
+
4
+ export default {
5
+ meta: {
6
+ type: "suggestion",
7
+ docs: {
8
+ description: "Enforce file extensions in import statements",
9
+ },
10
+ fixable: "code",
11
+ schema: [
12
+ {
13
+ type: "object",
14
+ properties: {
15
+ ignorePaths: {
16
+ type: "array",
17
+ items: { type: "string" },
18
+ },
19
+ includePaths: {
20
+ type: "array",
21
+ items: { type: "string" },
22
+ description: "Path patterns to include (e.g., '$lib/')",
23
+ },
24
+ tsToJs: {
25
+ type: "boolean",
26
+ description: "Convert .ts files to .js when importing",
27
+ },
28
+ aliases: {
29
+ type: "object",
30
+ description: "Map of path aliases to their actual paths (e.g., {'$lib': 'src/lib'})",
31
+ },
32
+ },
33
+ additionalProperties: false,
34
+ },
35
+ ],
36
+ messages: {
37
+ missingExtension: "Import should include a file extension",
38
+ noFileFound: "Import is missing extension and no matching file was found",
39
+ },
40
+ },
41
+ create(context) {
42
+ const options = context.options[0] || {};
43
+ const ignorePaths = options.ignorePaths || [];
44
+ const includePaths = options.includePaths || [];
45
+ const tsToJs = options.tsToJs !== undefined ? options.tsToJs : true; // Default to true
46
+ const aliases = options.aliases || {};
47
+
48
+ // Get the project root directory
49
+ const projectRoot = process.cwd();
50
+
51
+ // Utility function to resolve file paths
52
+ function resolveImportPath(importPath, currentFilePath) {
53
+ // Handle relative paths
54
+ if (importPath.startsWith("./") || importPath.startsWith("../")) {
55
+ return path.resolve(path.dirname(currentFilePath), importPath);
56
+ }
57
+
58
+ // Handle aliased paths
59
+ for (const [alias, aliasPath] of Object.entries(aliases)) {
60
+ // Check if the import starts with this alias
61
+ if (importPath === alias || importPath.startsWith(`${alias}/`)) {
62
+ // Replace the alias with the actual path
63
+ const relativePath = importPath === alias ? "" : importPath.slice(alias.length + 1); // +1 for the slash
64
+
65
+ // Convert the aliasPath to an absolute path
66
+ let absoluteAliasPath = aliasPath;
67
+ if (!path.isAbsolute(absoluteAliasPath)) {
68
+ absoluteAliasPath = path.resolve(projectRoot, aliasPath);
69
+ }
70
+
71
+ return path.join(absoluteAliasPath, relativePath);
72
+ }
73
+ }
74
+
75
+ return null;
76
+ }
77
+
78
+ // Find the file extension by checking which file exists
79
+ function findActualFile(basePath) {
80
+ if (!basePath) return null;
81
+
82
+ try {
83
+ // Get the directory and base name
84
+ const dir = path.dirname(basePath);
85
+ const base = path.basename(basePath);
86
+
87
+ // If the directory doesn't exist, return early
88
+ if (!fs.existsSync(dir)) {
89
+ return null;
90
+ }
91
+
92
+ // Read all files in the directory
93
+ const files = fs.readdirSync(dir);
94
+
95
+ // Look for files that match our base name plus any extension
96
+ for (const file of files) {
97
+ const fileParts = path.parse(file);
98
+
99
+ // If we find a file that matches our base name
100
+ if (fileParts.name === base) {
101
+ // Handle TypeScript to JavaScript conversion
102
+ if (tsToJs && fileParts.ext === ".ts") {
103
+ return {
104
+ actualPath: path.join(dir, file),
105
+ importExt: ".js", // Import as .js even though it's a .ts file
106
+ };
107
+ }
108
+
109
+ // Otherwise use the actual extension
110
+ return {
111
+ actualPath: path.join(dir, file),
112
+ importExt: fileParts.ext,
113
+ };
114
+ }
115
+ }
116
+ } catch (error) {
117
+ // If there's an error checking file existence, return null
118
+ console.error("Error checking files:", error);
119
+ }
120
+
121
+ return null;
122
+ }
123
+
124
+ return {
125
+ ImportDeclaration(node) {
126
+ const source = node.source.value;
127
+
128
+ // Check if it's a relative import or matches a manually specified include path
129
+ const isRelativeImport = source.startsWith("./") || source.startsWith("../");
130
+ const isAliasedPath = Object.keys(aliases).some(alias => source === alias || source.startsWith(`${alias}/`));
131
+ const isIncludedPath = includePaths.some(pattern => source.startsWith(pattern));
132
+
133
+ // Skip if it's not a relative import, aliased path, or included path
134
+ if (!isRelativeImport && !isAliasedPath && !isIncludedPath) {
135
+ return;
136
+ }
137
+
138
+ // Skip ignored paths
139
+ if (ignorePaths.some(path => source.includes(path))) {
140
+ return;
141
+ }
142
+
143
+ // Check if the import already has an extension
144
+ const hasExtension = path.extname(source) !== "";
145
+ if (!hasExtension) {
146
+ // Get current file path to resolve the import
147
+ const currentFilePath = context.getFilename();
148
+
149
+ // Try to determine the correct file by checking what exists
150
+ const resolvedPath = resolveImportPath(source, currentFilePath);
151
+ const fileInfo = findActualFile(resolvedPath);
152
+
153
+ context.report({
154
+ node,
155
+ messageId: fileInfo ? "missingExtension" : "noFileFound",
156
+ fix(fixer) {
157
+ // Only provide a fix if we found a file
158
+ if (fileInfo) {
159
+ // Replace the string literal with one that includes the extension
160
+ return fixer.replaceText(node.source, `"${source}${fileInfo.importExt}"`);
161
+ }
162
+
163
+ // Otherwise, don't try to fix
164
+ return null;
165
+ },
166
+ });
167
+ }
168
+ },
169
+ };
170
+ },
171
+ };
eslint.config.mjs CHANGED
@@ -6,6 +6,7 @@ import path from "node:path";
6
  import { fileURLToPath } from "node:url";
7
  import js from "@eslint/js";
8
  import { FlatCompat } from "@eslint/eslintrc";
 
9
 
10
  const __filename = fileURLToPath(import.meta.url);
11
  const __dirname = path.dirname(__filename);
@@ -41,6 +42,11 @@ export default [
41
  {
42
  plugins: {
43
  "@typescript-eslint": typescriptEslint,
 
 
 
 
 
44
  },
45
 
46
  languageOptions: {
@@ -72,6 +78,15 @@ export default [
72
 
73
  "object-shorthand": ["error", "always"],
74
  "svelte/no-at-html-tags": "off",
 
 
 
 
 
 
 
 
 
75
  },
76
  },
77
  {
 
6
  import { fileURLToPath } from "node:url";
7
  import js from "@eslint/js";
8
  import { FlatCompat } from "@eslint/eslintrc";
9
+ import enforceExt from "./eslint-rules/enforce-extensions.js";
10
 
11
  const __filename = fileURLToPath(import.meta.url);
12
  const __dirname = path.dirname(__filename);
 
42
  {
43
  plugins: {
44
  "@typescript-eslint": typescriptEslint,
45
+ "local": {
46
+ rules: {
47
+ "enforce-ext": enforceExt,
48
+ },
49
+ },
50
  },
51
 
52
  languageOptions: {
 
78
 
79
  "object-shorthand": ["error", "always"],
80
  "svelte/no-at-html-tags": "off",
81
+ "local/enforce-ext": [
82
+ "error",
83
+ {
84
+ includePaths: ["$lib/"],
85
+ aliases: {
86
+ $lib: "src/lib",
87
+ },
88
+ },
89
+ ],
90
  },
91
  },
92
  {
src/lib/components/InferencePlayground/InferencePlaygroundConversation.svelte CHANGED
@@ -1,5 +1,5 @@
1
  <script lang="ts">
2
- import type { Conversation } from "$lib/types";
3
 
4
  import { tick } from "svelte";
5
 
 
1
  <script lang="ts">
2
+ import type { Conversation } from "$lib/types.js";
3
 
4
  import { tick } from "svelte";
5
 
src/lib/components/InferencePlayground/InferencePlaygroundConversationHeader.svelte CHANGED
@@ -1,9 +1,9 @@
1
  <script lang="ts">
2
- import type { Conversation, ModelWithTokenizer } from "$lib/types";
3
 
4
  import { createEventDispatcher } from "svelte";
5
 
6
- import { models } from "$lib/stores/models";
7
  import Avatar from "../Avatar.svelte";
8
  import IconCog from "~icons/carbon/settings";
9
  import GenerationConfig from "./InferencePlaygroundGenerationConfig.svelte";
 
1
  <script lang="ts">
2
+ import type { Conversation, ModelWithTokenizer } from "$lib/types.js";
3
 
4
  import { createEventDispatcher } from "svelte";
5
 
6
+ import { models } from "$lib/stores/models.js";
7
  import Avatar from "../Avatar.svelte";
8
  import IconCog from "~icons/carbon/settings";
9
  import GenerationConfig from "./InferencePlaygroundGenerationConfig.svelte";
src/lib/components/InferencePlayground/InferencePlaygroundGenerationConfig.svelte CHANGED
@@ -1,8 +1,8 @@
1
  <script lang="ts">
2
- import type { Conversation } from "$lib/types";
3
 
4
- import { GENERATION_CONFIG_KEYS, GENERATION_CONFIG_SETTINGS } from "./generationConfigSettings";
5
- import { customMaxTokens } from "./inferencePlaygroundUtils";
6
 
7
  export let conversation: Conversation;
8
  export let classNames = "";
 
1
  <script lang="ts">
2
+ import type { Conversation } from "$lib/types.js";
3
 
4
+ import { GENERATION_CONFIG_KEYS, GENERATION_CONFIG_SETTINGS } from "./generationConfigSettings.js";
5
+ import { customMaxTokens } from "./inferencePlaygroundUtils.js";
6
 
7
  export let conversation: Conversation;
8
  export let classNames = "";
src/lib/components/InferencePlayground/InferencePlaygroundHFTokenModal.svelte CHANGED
@@ -1,5 +1,5 @@
1
  <script lang="ts">
2
- import { clickOutside } from "$lib/actions/click-outside";
3
  import { createEventDispatcher, onDestroy, onMount } from "svelte";
4
 
5
  import IconCross from "~icons/carbon/close";
 
1
  <script lang="ts">
2
+ import { clickOutside } from "$lib/actions/click-outside.js";
3
  import { createEventDispatcher, onDestroy, onMount } from "svelte";
4
 
5
  import IconCross from "~icons/carbon/close";
src/lib/components/InferencePlayground/InferencePlaygroundMessage.svelte CHANGED
@@ -1,6 +1,6 @@
1
  <script lang="ts">
2
  import { createEventDispatcher } from "svelte";
3
- import type { ConversationMessage } from "$lib/types";
4
 
5
  export let message: ConversationMessage;
6
  export let loading: boolean = false;
 
1
  <script lang="ts">
2
  import { createEventDispatcher } from "svelte";
3
+ import type { ConversationMessage } from "$lib/types.js";
4
 
5
  export let message: ConversationMessage;
6
  export let loading: boolean = false;
src/lib/components/InferencePlayground/InferencePlaygroundModelSelector.svelte CHANGED
@@ -1,12 +1,12 @@
1
  <script lang="ts">
2
- import type { Conversation, ModelWithTokenizer } from "$lib/types";
3
 
4
- import { models } from "$lib/stores/models";
5
  import IconCaret from "~icons/carbon/chevron-down";
6
  import Avatar from "../Avatar.svelte";
7
  import ModelSelectorModal from "./InferencePlaygroundModelSelectorModal.svelte";
8
  import ProviderSelect from "./InferencePlaygroundProviderSelect.svelte";
9
- import { defaultSystemMessage } from "./inferencePlaygroundUtils";
10
 
11
  export let conversation: Conversation;
12
 
 
1
  <script lang="ts">
2
+ import type { Conversation, ModelWithTokenizer } from "$lib/types.js";
3
 
4
+ import { models } from "$lib/stores/models.js";
5
  import IconCaret from "~icons/carbon/chevron-down";
6
  import Avatar from "../Avatar.svelte";
7
  import ModelSelectorModal from "./InferencePlaygroundModelSelectorModal.svelte";
8
  import ProviderSelect from "./InferencePlaygroundProviderSelect.svelte";
9
+ import { defaultSystemMessage } from "./inferencePlaygroundUtils.js";
10
 
11
  export let conversation: Conversation;
12
 
src/lib/components/InferencePlayground/InferencePlaygroundModelSelectorModal.svelte CHANGED
@@ -1,11 +1,11 @@
1
  <script lang="ts">
2
- import type { Conversation } from "$lib/types";
3
 
4
  import { createEventDispatcher, onMount, tick } from "svelte";
5
 
6
- import { models } from "$lib/stores/models";
7
- import { getTrending } from "$lib/utils/model";
8
- import fuzzysearch from "$lib/utils/search";
9
  import IconSearch from "~icons/carbon/search";
10
  import IconStar from "~icons/carbon/star";
11
 
 
1
  <script lang="ts">
2
+ import type { Conversation } from "$lib/types.js";
3
 
4
  import { createEventDispatcher, onMount, tick } from "svelte";
5
 
6
+ import { models } from "$lib/stores/models.js";
7
+ import { getTrending } from "$lib/utils/model.js";
8
+ import fuzzysearch from "$lib/utils/search.js";
9
  import IconSearch from "~icons/carbon/search";
10
  import IconStar from "~icons/carbon/star";
11
 
src/lib/components/InferencePlayground/InferencePlaygroundProviderSelect.svelte CHANGED
@@ -1,8 +1,8 @@
1
  <script lang="ts">
2
- import type { Conversation } from "$lib/types";
3
 
4
- import { randomPick } from "$lib/utils/array";
5
- import { cn } from "$lib/utils/cn";
6
  import { createSelect, createSync } from "@melt-ui/svelte";
7
  import IconCaret from "~icons/carbon/chevron-down";
8
  import IconProvider from "../Icons/IconProvider.svelte";
 
1
  <script lang="ts">
2
+ import type { Conversation } from "$lib/types.js";
3
 
4
+ import { randomPick } from "$lib/utils/array.js";
5
+ import { cn } from "$lib/utils/cn.js";
6
  import { createSelect, createSync } from "@melt-ui/svelte";
7
  import IconCaret from "~icons/carbon/chevron-down";
8
  import IconProvider from "../Icons/IconProvider.svelte";
src/lib/components/InferencePlayground/inferencePlaygroundUtils.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Conversation, ModelWithTokenizer } from "$lib/types";
2
  import type { InferenceSnippet } from "@huggingface/tasks";
3
  import { type ChatCompletionOutputMessage } from "@huggingface/tasks";
4
 
 
1
+ import type { Conversation, ModelWithTokenizer } from "$lib/types.js";
2
  import type { InferenceSnippet } from "@huggingface/tasks";
3
  import { type ChatCompletionOutputMessage } from "@huggingface/tasks";
4
 
src/lib/components/Prompts.svelte CHANGED
@@ -1,5 +1,5 @@
1
  <script lang="ts" context="module">
2
- import { clickOutside } from "$lib/actions/click-outside";
3
  import { writable } from "svelte/store";
4
  import IconCross from "~icons/carbon/close";
5
 
 
1
  <script lang="ts" context="module">
2
+ import { clickOutside } from "$lib/actions/click-outside.js";
3
  import { writable } from "svelte/store";
4
  import IconCross from "~icons/carbon/close";
5
 
src/lib/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { GenerationConfig } from "$lib/components/InferencePlayground/generationConfigSettings";
2
  import type { ChatCompletionInputMessage } from "@huggingface/tasks";
3
 
4
  export type ConversationMessage = Omit<ChatCompletionInputMessage, "content"> & { content?: string };
 
1
+ import type { GenerationConfig } from "$lib/components/InferencePlayground/generationConfigSettings.js";
2
  import type { ChatCompletionInputMessage } from "@huggingface/tasks";
3
 
4
  export type ConversationMessage = Omit<ChatCompletionInputMessage, "content"> & { content?: string };
src/lib/utils/effect.ts CHANGED
@@ -1,7 +1,7 @@
1
  import type { Stores, StoresValues } from "svelte/store";
2
  import { derived } from "svelte/store";
3
- import { safeOnDestroy } from "./lifecycle";
4
- import { noop } from "./noop";
5
 
6
  type EffectOptions = {
7
  /**
 
1
  import type { Stores, StoresValues } from "svelte/store";
2
  import { derived } from "svelte/store";
3
+ import { safeOnDestroy } from "./lifecycle.js";
4
+ import { noop } from "./noop.js";
5
 
6
  type EffectOptions = {
7
  /**
src/lib/utils/model.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ModelWithTokenizer } from "$lib/types";
2
 
3
  export function getTrending(models: ModelWithTokenizer[], limit = 5) {
4
  return models.toSorted((a, b) => b.trendingScore - a.trendingScore).slice(0, limit);
 
1
+ import type { ModelWithTokenizer } from "$lib/types.js";
2
 
3
  export function getTrending(models: ModelWithTokenizer[], limit = 5) {
4
  return models.toSorted((a, b) => b.trendingScore - a.trendingScore).slice(0, limit);
src/routes/+page.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { ModelWithTokenizer } from "$lib/types";
2
- import type { PageLoad } from "./$types";
3
 
4
  export const load: PageLoad = async ({ fetch }) => {
5
  const res = await fetch("/api/models");
 
1
+ import type { ModelWithTokenizer } from "$lib/types.js";
2
+ import type { PageLoad } from "./$types.js";
3
 
4
  export const load: PageLoad = async ({ fetch }) => {
5
  const res = await fetch("/api/models");
src/routes/api/models/+server.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { Model, ModelWithTokenizer } from "$lib/types";
2
  import { json } from "@sveltejs/kit";
3
- import type { RequestHandler } from "./$types";
4
  import { dev } from "$app/environment";
5
 
6
  let cache: ModelWithTokenizer[] | undefined;
 
1
+ import type { Model, ModelWithTokenizer } from "$lib/types.js";
2
  import { json } from "@sveltejs/kit";
3
+ import type { RequestHandler } from "./$types.js";
4
  import { dev } from "$app/environment";
5
 
6
  let cache: ModelWithTokenizer[] | undefined;