google / gts

☂️ TypeScript style guide, formatter, and linter.
https://github.com/google/gts
Apache License 2.0
5.08k stars 206 forks source link

How to apply lint to vue files in webpack? #308

Open akoidan opened 5 years ago

akoidan commented 5 years ago

Please check out vue-webpack-minimal template

npx vue-cli init deathangel908/vue-webpack-minimal folder-name
cd folder-name
npm run check

Expected: gts will check .vue files Actual: gts ignores vue files, like App.vue

Is there's a way to configure gts with vue and webpack?

ofrobots commented 5 years ago

@akoidan I am not very familiar with Vue, and the repro you provided doesn't quite work (there is no check script). Can you provide a full repro?

I have an expectation that this will work on the next tag as we use switched to prettier which should have better handling of vue files. You will need to ensure that you adjust your tsconfig.json include property to ensure the *.vue files are in the project.

akoidan commented 5 years ago

@ofrobots I created minimal example on github gts-308. It uses webpack and tslint to process vue files. So tslint-loader processes .vue files by rules defined in tslint.json.

Is there a way I can make gts to do this?

If you run npm start you will see tslint warning, but if you run npm run check it will only show warnings from main.ts, but not in App.vue. You can check TODOs in source code.

We can apply loader like that in webpack config:

ofrobots commented 5 years ago

@akoidan Thanks that helps. It seems that the TypeScript programmatic API createProgram filters vue files by default. This will require some implementation effort to support. Supporting prettier should be straightforward with the following change:

diff --git a/src/lint.ts b/src/lint.ts
index 6941a1b..52b967f 100644
--- a/src/lint.ts
+++ b/src/lint.ts
@@ -93,6 +93,36 @@ export function lint(
 }

 export function createProgram(options: Options): ts.Program {
+  const extraExtensions = ['vue'];
+  const parseConfigHost = {
+    fileExists: ts.sys.fileExists,
+    readDirectory: (
+      rootDir: string,
+      extensions?: ReadonlyArray<string>,
+      excludes?: ReadonlyArray<string>,
+      includes?: ReadonlyArray<string>,
+      depth?: number
+    ) =>
+      ts.sys.readDirectory(
+        rootDir,
+        (extensions || []).concat(extraExtensions),
+        excludes,
+        includes,
+        depth
+      ),
+    readFile: ts.sys.readFile,
+    useCaseSensitiveFileNames: true,
+  };
   const tsconfigPath = path.join(options.targetRootDir, 'tsconfig.json');
-  return Linter.createProgram(tsconfigPath);
+  const tsconfig = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
+  const parsed = ts.parseJsonConfigFileContent(
+    tsconfig,
+    parseConfigHost,
+    path.dirname(tsconfigPath)
+  );
+  parsed.options.allowNonTsExtensions = true;
+
+  var host = ts.createCompilerHost(parsed.options, true);
+  var program = ts.createProgram(parsed.fileNames, parsed.options, host);
+  return program;
 }

Supporting tslint will probably require more effort. I'll see when I can get this this, but contributions are welcome :).