`", { rules: { "no-unclosed-tag": true } });
7 | hasDiagnostic(t, diagnostics, "no-unclosed-tag");
8 | });
9 |
10 | tsTest("Don't report self closed tags", t => {
11 | const { diagnostics } = getDiagnostics("html`
![]()
`", { rules: { "no-unclosed-tag": true } });
12 | hasNoDiagnostics(t, diagnostics);
13 | });
14 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/src/test/rules/no-unintended-mixed-binding.ts:
--------------------------------------------------------------------------------
1 | import { getDiagnostics } from "../helpers/analyze.js";
2 | import { hasDiagnostic, hasNoDiagnostics } from "../helpers/assert.js";
3 | import { tsTest } from "../helpers/ts-test.js";
4 |
5 | tsTest('Report mixed binding with expression and "', t => {
6 | const { diagnostics } = getDiagnostics('html`
`');
7 | hasDiagnostic(t, diagnostics, "no-unintended-mixed-binding");
8 | });
9 |
10 | tsTest("Report mixed binding with expression and '", t => {
11 | const { diagnostics } = getDiagnostics("html`
`");
12 | hasDiagnostic(t, diagnostics, "no-unintended-mixed-binding");
13 | });
14 |
15 | tsTest("Report mixed binding with expression and }", t => {
16 | const { diagnostics } = getDiagnostics("html`
`");
17 | hasDiagnostic(t, diagnostics, "no-unintended-mixed-binding");
18 | });
19 |
20 | tsTest("Report mixed binding with expression and /", t => {
21 | const { diagnostics } = getDiagnostics("html`
`");
22 | hasDiagnostic(t, diagnostics, "no-unintended-mixed-binding");
23 | });
24 |
25 | tsTest("Don't report mixed binding with expression and %", t => {
26 | const { diagnostics } = getDiagnostics("html`
`");
27 | hasNoDiagnostics(t, diagnostics);
28 | });
29 |
30 | tsTest("Don't report mixed event listener binding directly followed by /", t => {
31 | const { diagnostics } = getDiagnostics("html`
`");
32 | hasNoDiagnostics(t, diagnostics);
33 | });
34 |
35 | tsTest("Report mixed binding with expression and } inside quotes", t => {
36 | const { diagnostics } = getDiagnostics('html`
`');
37 | hasDiagnostic(t, diagnostics, "no-unintended-mixed-binding");
38 | });
39 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/src/test/rules/no-unknown-attribute.ts:
--------------------------------------------------------------------------------
1 | import { getDiagnostics } from "../helpers/analyze.js";
2 | import { hasDiagnostic, hasNoDiagnostics } from "../helpers/assert.js";
3 | import { tsTest } from "../helpers/ts-test.js";
4 |
5 | tsTest("Don't report unknown attributes when 'no-unknown-attribute' is turned off", t => {
6 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-attribute": false } });
7 | hasNoDiagnostics(t, diagnostics);
8 | });
9 |
10 | tsTest("Report unknown attributes on known element", t => {
11 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-attribute": true } });
12 | hasDiagnostic(t, diagnostics, "no-unknown-attribute");
13 | });
14 |
15 | tsTest("Don't report unknown attributes", t => {
16 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-attribute": true } });
17 | hasNoDiagnostics(t, diagnostics);
18 | });
19 |
20 | tsTest("Don't report unknown attributes on unknown element", t => {
21 | const { diagnostics } = getDiagnostics("html`
`", {
22 | rules: { "no-unknown-attribute": true, "no-unknown-tag-name": false }
23 | });
24 | hasNoDiagnostics(t, diagnostics);
25 | });
26 |
27 | tsTest("Don't report unknown data- attributes", t => {
28 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-attribute": true } });
29 | hasNoDiagnostics(t, diagnostics);
30 | });
31 |
32 | tsTest("Don't report element expressions", t => {
33 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-attribute": true } });
34 | hasNoDiagnostics(t, diagnostics);
35 | });
36 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/src/test/rules/no-unknown-event.ts:
--------------------------------------------------------------------------------
1 | import { getDiagnostics } from "../helpers/analyze.js";
2 | import { hasDiagnostic, hasNoDiagnostics } from "../helpers/assert.js";
3 | import { tsTest } from "../helpers/ts-test.js";
4 |
5 | tsTest("Don't report unknown events when 'no-unknown-event' is turned off", t => {
6 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-event": false } });
7 | hasNoDiagnostics(t, diagnostics);
8 | });
9 |
10 | tsTest("Report unknown events on known element", t => {
11 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-event": true } });
12 | hasDiagnostic(t, diagnostics, "no-unknown-event");
13 | });
14 |
15 | tsTest("Don't report known events", t => {
16 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-event": true } });
17 | hasNoDiagnostics(t, diagnostics);
18 | });
19 |
20 | tsTest("Don't report unknown events on unknown element", t => {
21 | const { diagnostics } = getDiagnostics("html`
`", {
22 | rules: { "no-unknown-event": true, "no-unknown-tag-name": false }
23 | });
24 | hasNoDiagnostics(t, diagnostics);
25 | });
26 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/src/test/rules/no-unknown-property.ts:
--------------------------------------------------------------------------------
1 | import { getDiagnostics } from "../helpers/analyze.js";
2 | import { hasDiagnostic, hasNoDiagnostics } from "../helpers/assert.js";
3 | import { makeElement } from "../helpers/generate-test-file.js";
4 | import { tsTest } from "../helpers/ts-test.js";
5 |
6 | tsTest("Don't report unknown properties when 'no-unknown-property' is turned off", t => {
7 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-property": false } });
8 | hasNoDiagnostics(t, diagnostics);
9 | });
10 |
11 | tsTest("Report unknown properties on known element", t => {
12 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-property": true } });
13 | hasDiagnostic(t, diagnostics, "no-unknown-property");
14 | });
15 |
16 | tsTest("Don't report known properties", t => {
17 | const { diagnostics } = getDiagnostics([makeElement({ properties: ["foo: string"] }), "html`
`"], {
18 | rules: { "no-unknown-property": true }
19 | });
20 | hasNoDiagnostics(t, diagnostics);
21 | });
22 |
23 | tsTest("Don't report unknown properties on unknown element", t => {
24 | const { diagnostics } = getDiagnostics("html`
`", {
25 | rules: { "no-unknown-property": true, "no-unknown-tag-name": false }
26 | });
27 | hasNoDiagnostics(t, diagnostics);
28 | });
29 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/src/test/rules/no-unknown-slot.ts:
--------------------------------------------------------------------------------
1 | import { getDiagnostics } from "../helpers/analyze.js";
2 | import { hasDiagnostic, hasNoDiagnostics } from "../helpers/assert.js";
3 | import { makeElement } from "../helpers/generate-test-file.js";
4 | import { tsTest } from "../helpers/ts-test.js";
5 |
6 | tsTest("Report unknown slot name", t => {
7 | const { diagnostics } = getDiagnostics([makeElement({ slots: ["foo"] }), "html`
`"], {
8 | rules: { "no-unknown-slot": true }
9 | });
10 | hasDiagnostic(t, diagnostics, "no-unknown-slot");
11 | });
12 |
13 | tsTest("Don't report known slot name", t => {
14 | const { diagnostics } = getDiagnostics([makeElement({ slots: ["foo"] }), "html`
`"], {
15 | rules: { "no-unknown-slot": true }
16 | });
17 | hasNoDiagnostics(t, diagnostics);
18 | });
19 |
20 | tsTest("Don't report known, unnamed slot name", t => {
21 | const { diagnostics } = getDiagnostics([makeElement({ slots: [""] }), "html`
`"], {
22 | rules: { "no-unknown-slot": true }
23 | });
24 | hasNoDiagnostics(t, diagnostics);
25 | });
26 |
27 | tsTest("Report missing slot attribute", t => {
28 | const { diagnostics } = getDiagnostics([makeElement({ slots: ["foo"] }), "html`
`"], {
29 | rules: { "no-unknown-slot": true }
30 | });
31 | hasDiagnostic(t, diagnostics, "no-unknown-slot");
32 | });
33 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/src/test/rules/no-unknown-tag-name.ts:
--------------------------------------------------------------------------------
1 | import { getDiagnostics } from "../helpers/analyze.js";
2 | import { hasDiagnostic, hasNoDiagnostics } from "../helpers/assert.js";
3 | import { makeElement } from "../helpers/generate-test-file.js";
4 | import { tsTest } from "../helpers/ts-test.js";
5 |
6 | tsTest("Report unknown custom elements", t => {
7 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-tag-name": true } });
8 | hasDiagnostic(t, diagnostics, "no-unknown-tag-name");
9 | });
10 |
11 | tsTest("Don't report known built in elements", t => {
12 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-tag-name": true } });
13 | hasNoDiagnostics(t, diagnostics);
14 | });
15 |
16 | tsTest("Report unknown built in elements", t => {
17 | const { diagnostics } = getDiagnostics("html`
`", { rules: { "no-unknown-tag-name": true } });
18 | hasDiagnostic(t, diagnostics, "no-unknown-tag-name");
19 | });
20 |
21 | tsTest("Don't report known custom elements found in other file", t => {
22 | const { diagnostics } = getDiagnostics([makeElement({}), "html`
`"], { rules: { "no-unknown-tag-name": true } });
23 | hasNoDiagnostics(t, diagnostics);
24 | });
25 |
26 | tsTest("Don't report known custom element", t => {
27 | const { diagnostics } = getDiagnostics(
28 | "class MyElement extends HTMLElement {}; customElements.define('my-element', MyElement); html`
`",
29 | {
30 | rules: { "no-unknown-tag-name": true }
31 | }
32 | );
33 | hasNoDiagnostics(t, diagnostics);
34 | });
35 |
--------------------------------------------------------------------------------
/packages/lit-analyzer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "include": ["./src"],
4 | "exclude": [],
5 | "compilerOptions": {
6 | "rootDir": "./src",
7 | "outDir": "./",
8 | "resolveJsonModule": true,
9 | "tsBuildInfoFile": "./.tsbuildinfo"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/index.js:
--------------------------------------------------------------------------------
1 | // A TypeScript compiler plugin must do a CJS style default export, but
2 | // we can't express that in proper ESM, so this hand-written JS
3 | // file bridges the difference.
4 |
5 | module.exports = require("./lib/index").init;
6 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ts-lit-plugin",
3 | "version": "2.0.2",
4 | "description": "Typescript plugin that adds type checking and code completion to lit-html",
5 | "author": "runem",
6 | "license": "MIT",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/runem/lit-analyzer.git"
10 | },
11 | "keywords": [
12 | "lit-html",
13 | "lit",
14 | "lit-element",
15 | "javascript",
16 | "typescript",
17 | "web components",
18 | "web",
19 | "components",
20 | "tagged",
21 | "template"
22 | ],
23 | "scripts": {
24 | "watch": "tsc --watch",
25 | "build": "wireit",
26 | "test": "wireit",
27 | "readme": "readme generate -i readme.blueprint.md -c readme.config.json"
28 | },
29 | "wireit": {
30 | "build": {
31 | "dependencies": [
32 | "../lit-analyzer:build"
33 | ],
34 | "command": "tsc --build --pretty",
35 | "files": [
36 | "src/**/*",
37 | "tsconfig.json"
38 | ],
39 | "output": [
40 | "lib",
41 | "./tsbuildinfo"
42 | ],
43 | "clean": "if-file-deleted"
44 | },
45 | "test": {
46 | "dependencies": [
47 | "build"
48 | ]
49 | }
50 | },
51 | "main": "index.js",
52 | "files": [
53 | "/lib/",
54 | "/html-documentation/"
55 | ],
56 | "dependencies": {
57 | "lit-analyzer": "^2.0.1",
58 | "web-component-analyzer": "^2.0.0"
59 | },
60 | "devDependencies": {
61 | "@types/node": "^14.0.13",
62 | "esbuild": "^0.14.34",
63 | "rimraf": "^3.0.2",
64 | "typescript": "~5.2.2",
65 | "wireit": "^0.1.1"
66 | },
67 | "contributors": [
68 | {
69 | "name": "Rune Mehlsen",
70 | "url": "https://twitter.com/runemehlsen",
71 | "img": "https://avatars2.githubusercontent.com/u/5372940?s=460&v=4"
72 | },
73 | {
74 | "name": "Andreas Mehlsen",
75 | "url": "https://twitter.com/andreasmehlsen",
76 | "img": "https://avatars1.githubusercontent.com/u/6267397?s=460&v=4"
77 | },
78 | {
79 | "name": "You?",
80 | "img": "https://joeschmoe.io/api/v1/random",
81 | "url": "https://github.com/runem/lit-analyzer/blob/master/CONTRIBUTING.md"
82 | }
83 | ]
84 | }
85 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/readme.blueprint.md:
--------------------------------------------------------------------------------
1 | {{ template:title }}
2 | {{ template:description }}
3 | {{ template:badges }}
4 |
5 | {{ load:./readme/header.md }}
6 |
7 | {{ load:./readme/install.md }}
8 | {{ load:./readme/config.md }}
9 | {{ load:./../../docs/readme/rules.md }}
10 | {{ load:./../../docs/readme/jsdoc.md }}
11 |
12 | {{ template:contributors }}
13 | {{ template:license }}
14 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/readme.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "line": "rainbow",
3 | "ids": {
4 | "github": "runem/lit-analyzer",
5 | "npm": "ts-lit-plugin"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/readme/config.md:
--------------------------------------------------------------------------------
1 | ## Configuration
2 |
3 | You can configure this plugin through your `tsconfig.json`.
4 |
5 | ### Example
6 |
7 |
8 | ```json
9 | {
10 | "compilerOptions": {
11 | "plugins": [
12 | {
13 | "name": "ts-lit-plugin",
14 | "strict": true,
15 | "rules": {
16 | "no-unknown-tag-name": "off",
17 | "no-unknown-event": "warn"
18 | }
19 | }
20 | ]
21 | }
22 | }
23 | ```
24 |
25 | ### Available options
26 |
27 | {{ load:./../../docs/readme/config-table.md }}
28 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/readme/header.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/readme/install.md:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | First, install the plugin:
4 |
5 |
6 | ```bash
7 | npm install ts-lit-plugin -D
8 | ```
9 |
10 | Then add a `plugins` section to your [`tsconfig.json`](http://www.typescriptlang.org/docs/handbook/tsconfig-json.html):
11 |
12 |
13 | ```json
14 | {
15 | "compilerOptions": {
16 | "plugins": [
17 | {
18 | "name": "ts-lit-plugin"
19 | }
20 | ]
21 | }
22 | }
23 | ```
24 |
25 | Finally, restart you Typescript Language Service, and you should start getting diagnostics from `ts-lit-plugin`.
26 |
27 | **Note:**
28 |
29 | - If you use Visual Studio Code you can also install the [lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin) extension.
30 | - If you would rather use a CLI, you can install the [lit-analyzer](https://github.com/runem/lit-analyzer/blob/master/packages/lit-analyzer).
31 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/bazel-plugin.ts:
--------------------------------------------------------------------------------
1 | import { DefaultLitAnalyzerContext, LitAnalyzer, LitAnalyzerConfig, LitAnalyzerContext, makeConfig } from "lit-analyzer";
2 | import ts, { Diagnostic } from "typescript";
3 | import { translateDiagnostics } from "./ts-lit-plugin/translate/translate-diagnostics.js";
4 |
5 | // See https://github.com/bazelbuild/rules_typescript/blob/master/internal/tsc_wrapped/plugin_api.ts
6 | interface DiagnosticPlugin {
7 | readonly name: string;
8 | getDiagnostics(sourceFile: ts.SourceFile): Readonly
[];
9 | }
10 |
11 | /**
12 | * Implements bazel's DiagnosticPlugin interface, so that we can run
13 | * the ts-lit-plugin checks as part of bazel compilation.
14 | */
15 | export class Plugin implements DiagnosticPlugin {
16 | public readonly name = "lit";
17 |
18 | private readonly context: LitAnalyzerContext;
19 | private readonly analyzer: LitAnalyzer;
20 |
21 | constructor(program: ts.Program, config: LitAnalyzerConfig) {
22 | this.name = "lit";
23 | const context = new DefaultLitAnalyzerContext({
24 | getProgram() {
25 | return program;
26 | }
27 | });
28 | context.updateConfig(makeConfig(config));
29 | this.context = context;
30 | this.analyzer = new LitAnalyzer(context);
31 | }
32 |
33 | getDiagnostics(sourceFile: ts.SourceFile): Diagnostic[] {
34 | const litDiagnostics = this.analyzer.getDiagnosticsInFile(sourceFile);
35 |
36 | const diagnostics = translateDiagnostics(litDiagnostics, sourceFile, this.context);
37 | for (const diagnostic of diagnostics) {
38 | if (diagnostic.category === ts.DiagnosticCategory.Warning) {
39 | // In bazel something is either an error that breaks the build, or
40 | // we don't want to report it at all.
41 | diagnostic.category = ts.DiagnosticCategory.Error;
42 | }
43 | }
44 | return diagnostics;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/lit-plugin-context.ts:
--------------------------------------------------------------------------------
1 | import { DefaultLitAnalyzerContext, LitAnalyzerConfig } from "lit-analyzer";
2 | import { logger } from "../logger.js";
3 |
4 | export class LitPluginContext extends DefaultLitAnalyzerContext {
5 | logger = logger;
6 |
7 | public updateConfig(config: LitAnalyzerConfig): void {
8 | const hasChangedLogging = config.logging !== "off" && (this.config.logging !== config.logging || this.config.cwd !== config.cwd);
9 |
10 | // Setup logging
11 | this.logger.cwd = config.cwd;
12 |
13 | super.updateConfig(config);
14 |
15 | if (hasChangedLogging) {
16 | this.logger.resetLogs();
17 | }
18 |
19 | logger.debug("Updating the config", config);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-code-fixes.ts:
--------------------------------------------------------------------------------
1 | import { LitCodeFix, LitCodeFixAction } from "lit-analyzer";
2 | import { CodeFixAction, FileTextChanges, SourceFile } from "typescript";
3 | import { translateRange } from "./translate-range.js";
4 |
5 | export function translateCodeFixes(codeFixes: LitCodeFix[], file: SourceFile): CodeFixAction[] {
6 | return codeFixes.map(codeFix => translateCodeFix(file, codeFix));
7 | }
8 |
9 | export function translateCodeFix(file: SourceFile, codeFix: LitCodeFix): CodeFixAction {
10 | return {
11 | fixName: codeFix.name,
12 | description: codeFix.message,
13 | changes: codeFix.actions.map(action => translateCodeFixAction(file, action))
14 | };
15 | }
16 |
17 | function translateCodeFixAction(file: SourceFile, action: LitCodeFixAction): FileTextChanges {
18 | return {
19 | fileName: file.fileName,
20 | textChanges: [
21 | {
22 | span: translateRange(action.range),
23 | newText: action.newText
24 | }
25 | ]
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-completion-details.ts:
--------------------------------------------------------------------------------
1 | import { LitCompletionDetails } from "lit-analyzer";
2 | import { CompletionEntryDetails } from "typescript";
3 | import { LitPluginContext } from "../lit-plugin-context.js";
4 |
5 | export function translateCompletionDetails(completionDetails: LitCompletionDetails, context: LitPluginContext): CompletionEntryDetails {
6 | return {
7 | name: completionDetails.name,
8 | kind: context.ts.ScriptElementKind.label,
9 | kindModifiers: "",
10 | displayParts: [
11 | {
12 | text: completionDetails.primaryInfo,
13 | kind: "text"
14 | }
15 | ],
16 | documentation:
17 | completionDetails.secondaryInfo == null
18 | ? []
19 | : [
20 | {
21 | kind: "text",
22 | text: completionDetails.secondaryInfo
23 | }
24 | ]
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-completions.ts:
--------------------------------------------------------------------------------
1 | import { LitCompletion } from "lit-analyzer";
2 | import { CompletionEntry, CompletionInfo } from "typescript";
3 | import { translateRange } from "./translate-range.js";
4 | import { translateTargetKind } from "./translate-target-kind.js";
5 |
6 | export function translateCompletions(completions: LitCompletion[]): CompletionInfo | undefined {
7 | const entries = completions.map(completion => translateCompletion(completion));
8 |
9 | if (entries != null && entries.length > 0) {
10 | return {
11 | isGlobalCompletion: false,
12 | isMemberCompletion: false,
13 | isNewIdentifierLocation: false,
14 | entries
15 | };
16 | }
17 |
18 | return undefined;
19 | }
20 |
21 | function translateCompletion(completion: LitCompletion): CompletionEntry {
22 | const { importance, kind, insert, name, range } = completion;
23 |
24 | return {
25 | name,
26 | kind: translateTargetKind(kind),
27 | kindModifiers: completion.kindModifiers,
28 | sortText: completion.sortText != null ? completion.sortText : importance === "high" ? "0" : importance === "medium" ? "1" : "2",
29 | insertText: insert,
30 | ...(range != null ? { replacementSpan: translateRange(range) } : {})
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-definition.ts:
--------------------------------------------------------------------------------
1 | import { LitDefinition, LitDefinitionTarget } from "lit-analyzer";
2 | import { DefinitionInfo, DefinitionInfoAndBoundSpan } from "typescript";
3 | import { tsModule } from "../../ts-module.js";
4 | import { translateRange } from "./translate-range.js";
5 |
6 | export function translateDefinition(definition: LitDefinition): DefinitionInfoAndBoundSpan {
7 | return {
8 | definitions: definition.targets.map(translateDefinitionInfo),
9 | textSpan: translateRange(definition.fromRange)
10 | };
11 | }
12 |
13 | function translateDefinitionInfo(target: LitDefinitionTarget): DefinitionInfo {
14 | let targetStart: number;
15 | let targetEnd: number;
16 | let targetFileName: string;
17 | let targetName: string;
18 |
19 | switch (target.kind) {
20 | case "range":
21 | targetStart = target.range.start;
22 | targetEnd = target.range.end;
23 | targetFileName = target.sourceFile.fileName;
24 | targetName = target.name || "";
25 | break;
26 |
27 | case "node": {
28 | const node = target.node;
29 | targetStart = node.getStart();
30 | targetEnd = node.getEnd();
31 | targetFileName = node.getSourceFile().fileName;
32 | targetName = target.name || (tsModule.ts.isIdentifier(node) ? node.getText() : "");
33 | break;
34 | }
35 | }
36 |
37 | return {
38 | name: targetName,
39 | textSpan: {
40 | start: targetStart,
41 | length: targetEnd - targetStart
42 | },
43 | fileName: targetFileName,
44 | containerName: targetFileName,
45 | kind: tsModule.ts.ScriptElementKind.memberVariableElement,
46 | containerKind: tsModule.ts.ScriptElementKind.functionElement
47 | };
48 | }
49 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-diagnostics.ts:
--------------------------------------------------------------------------------
1 | import { LitAnalyzerContext, LitDiagnostic } from "lit-analyzer";
2 | import { DiagnosticMessageChain, DiagnosticWithLocation, SourceFile } from "typescript";
3 | import { translateRange } from "./translate-range.js";
4 |
5 | export function translateDiagnostics(reports: LitDiagnostic[], file: SourceFile, context: LitAnalyzerContext): DiagnosticWithLocation[] {
6 | return reports.map(report => translateDiagnostic(report, file, context));
7 | }
8 |
9 | /**
10 | * Convert a diagnostic into a "message" that can be shown to the user.
11 | * @param diagnostic
12 | */
13 | function getMessageTextFromDiagnostic(diagnostic: LitDiagnostic): string {
14 | return `${diagnostic.message}${diagnostic.fixMessage == null ? "" : ` ${diagnostic.fixMessage}`}`;
15 | }
16 |
17 | function translateDiagnostic(diagnostic: LitDiagnostic, file: SourceFile, context: LitAnalyzerContext): DiagnosticWithLocation {
18 | const span = translateRange(diagnostic.location);
19 |
20 | const category = diagnostic.severity === "error" ? context.ts.DiagnosticCategory.Error : context.ts.DiagnosticCategory.Warning;
21 | const code = diagnostic.code ?? 0;
22 | const messageText: string | DiagnosticMessageChain =
23 | !context.config.dontShowSuggestions && diagnostic.suggestion
24 | ? {
25 | messageText: getMessageTextFromDiagnostic(diagnostic),
26 | code,
27 | category,
28 | next: [
29 | {
30 | messageText: diagnostic.suggestion,
31 | code: 0,
32 | category: context.ts.DiagnosticCategory.Suggestion
33 | }
34 | ]
35 | }
36 | : getMessageTextFromDiagnostic(diagnostic);
37 |
38 | if (Number(context.ts.versionMajorMinor) < 3.6 && typeof messageText !== "string") {
39 | // The format of DiagnosticMessageChain#next changed in 3.6 to be an array.
40 | // This check for backwards compatibility
41 | if (messageText.next != null && Array.isArray(messageText.next)) {
42 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
43 | messageText.next = messageText.next[0] as any;
44 | }
45 | }
46 |
47 | return {
48 | ...span,
49 | file,
50 | messageText,
51 | category,
52 | code,
53 | source: diagnostic.source == null ? undefined : `lit-plugin(${diagnostic.source})`
54 | };
55 | }
56 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-format-edits.ts:
--------------------------------------------------------------------------------
1 | import { LitFormatEdit } from "lit-analyzer";
2 | import * as ts from "typescript";
3 | import { translateRange } from "./translate-range.js";
4 |
5 | export function translateFormatEdits(formatEdits: LitFormatEdit[]): ts.TextChange[] {
6 | return formatEdits.map(formatEdit => translateFormatEdit(formatEdit));
7 | }
8 |
9 | function translateFormatEdit(formatEdit: LitFormatEdit): ts.TextChange {
10 | return {
11 | newText: formatEdit.newText,
12 | span: translateRange(formatEdit.range)
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-outlining-spans.ts:
--------------------------------------------------------------------------------
1 | import { LitOutliningSpan } from "lit-analyzer";
2 | import { translateRange } from "./translate-range.js";
3 | import type * as ts from "typescript";
4 |
5 | export function translateOutliningSpans(outliningSpans: LitOutliningSpan[]): ts.OutliningSpan[] {
6 | return outliningSpans.map(outliningSpan => translateOutliningSpan(outliningSpan));
7 | }
8 |
9 | function translateOutliningSpan(outliningSpan: LitOutliningSpan): ts.OutliningSpan {
10 | const span = translateRange(outliningSpan.location);
11 |
12 | return {
13 | autoCollapse: outliningSpan.autoCollapse || false,
14 | textSpan: span,
15 | hintSpan: span,
16 | kind: outliningSpan.kind as unknown as ts.OutliningSpanKind,
17 | bannerText: outliningSpan.bannerText
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-quick-info.ts:
--------------------------------------------------------------------------------
1 | import { LitQuickInfo } from "lit-analyzer";
2 | import { QuickInfo } from "typescript";
3 | import { tsModule } from "../../ts-module.js";
4 | import { translateRange } from "./translate-range.js";
5 |
6 | export function translateQuickInfo(quickInfo: LitQuickInfo): QuickInfo {
7 | return {
8 | kind: tsModule.ts.ScriptElementKind.label,
9 | kindModifiers: "",
10 | textSpan: translateRange(quickInfo.range),
11 | displayParts: [
12 | {
13 | text: quickInfo.primaryInfo,
14 | kind: "text"
15 | }
16 | ],
17 | documentation:
18 | quickInfo.secondaryInfo == null
19 | ? []
20 | : [
21 | {
22 | kind: "text",
23 | text: quickInfo.secondaryInfo
24 | }
25 | ]
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-range.ts:
--------------------------------------------------------------------------------
1 | import { Range } from "lit-analyzer";
2 | import { TextSpan } from "typescript";
3 |
4 | export function translateRange(range: Range): TextSpan {
5 | return {
6 | start: range.start,
7 | length: range.end - range.start
8 | };
9 | }
10 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-rename-info.ts:
--------------------------------------------------------------------------------
1 | import { LitRenameInfo } from "lit-analyzer";
2 | import { RenameInfo } from "typescript";
3 | import { translateTargetKind } from "./translate-target-kind.js";
4 | import { translateRange } from "./translate-range.js";
5 |
6 | export function translateRenameInfo({ displayName, fullDisplayName, kind, range }: LitRenameInfo): RenameInfo {
7 | const triggerSpan = translateRange(range);
8 |
9 | return {
10 | canRename: true,
11 | kind: translateTargetKind(kind),
12 | kindModifiers: "",
13 | displayName,
14 | fullDisplayName,
15 | triggerSpan
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-rename-locations.ts:
--------------------------------------------------------------------------------
1 | import { LitRenameLocation } from "lit-analyzer";
2 | import { translateRange } from "./translate-range.js";
3 | import { RenameLocation } from "typescript";
4 |
5 | export function translateRenameLocations(renameLocations: LitRenameLocation[]): RenameLocation[] {
6 | return renameLocations.map(renameLocation => translateRenameLocation(renameLocation));
7 | }
8 |
9 | function translateRenameLocation({ fileName, prefixText, suffixText, range }: LitRenameLocation): RenameLocation {
10 | const textSpan = translateRange(range);
11 |
12 | return {
13 | textSpan,
14 | fileName,
15 | prefixText,
16 | suffixText
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-lit-plugin/translate/translate-target-kind.ts:
--------------------------------------------------------------------------------
1 | import { LitTargetKind } from "lit-analyzer";
2 | import { ScriptElementKind } from "typescript";
3 | import { tsModule } from "../../ts-module.js";
4 |
5 | export function translateTargetKind(kind: LitTargetKind): ScriptElementKind {
6 | switch (kind) {
7 | case "memberFunctionElement":
8 | return tsModule.ts.ScriptElementKind.memberFunctionElement;
9 | case "functionElement":
10 | return tsModule.ts.ScriptElementKind.functionElement;
11 | case "constructorImplementationElement":
12 | return tsModule.ts.ScriptElementKind.constructorImplementationElement;
13 | case "variableElement":
14 | return tsModule.ts.ScriptElementKind.variableElement;
15 | case "classElement":
16 | return tsModule.ts.ScriptElementKind.classElement;
17 | case "interfaceElement":
18 | return tsModule.ts.ScriptElementKind.interfaceElement;
19 | case "moduleElement":
20 | return tsModule.ts.ScriptElementKind.moduleElement;
21 | case "memberVariableElement":
22 | case "member":
23 | return tsModule.ts.ScriptElementKind.memberVariableElement;
24 | case "constElement":
25 | return tsModule.ts.ScriptElementKind.constElement;
26 | case "enumElement":
27 | return tsModule.ts.ScriptElementKind.enumElement;
28 | case "keyword":
29 | return tsModule.ts.ScriptElementKind.keyword;
30 | case "alias":
31 | return tsModule.ts.ScriptElementKind.alias;
32 | case "label":
33 | return tsModule.ts.ScriptElementKind.label;
34 | default:
35 | return tsModule.ts.ScriptElementKind.unknown;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/src/ts-module.ts:
--------------------------------------------------------------------------------
1 | import * as tsModuleType from "typescript";
2 |
3 | export const tsModule: { ts: typeof tsModuleType } = { ts: tsModuleType };
4 |
5 | export function setTypescriptModule(newModule: typeof tsModuleType): void {
6 | tsModule.ts = newModule;
7 | }
8 |
--------------------------------------------------------------------------------
/packages/ts-lit-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "include": ["./src"],
4 | "compilerOptions": {
5 | "outDir": "./lib",
6 | "tsBuildInfoFile": "./.tsbuildinfo"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | // A launch configuration that compiles the extension and then opens it inside a new window
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | {
6 | "version": "0.2.0",
7 | "configurations": [
8 | {
9 | "name": "Extension",
10 | "type": "extensionHost",
11 | "request": "launch",
12 | "runtimeExecutable": "${execPath}",
13 | "args": ["--extensionDevelopmentPath=${workspaceFolder}"],
14 | "outFiles": ["${workspaceFolder}/out/**/*.js"],
15 | "preLaunchTask": "npm: watch"
16 | },
17 | {
18 | "name": "Extension Tests",
19 | "type": "extensionHost",
20 | "request": "launch",
21 | "runtimeExecutable": "${execPath}",
22 | "args": ["--extensionDevelopmentPath=${workspaceFolder}", "--extensionTestsPath=${workspaceFolder}/out/test"],
23 | "outFiles": ["${workspaceFolder}/out/test/**/*.js"],
24 | "preLaunchTask": "npm: watch"
25 | }
26 | ]
27 | }
28 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "files.exclude": {
4 | "out": false // set this to true to hide the "out" folder with the compiled JS files
5 | },
6 | "search.exclude": {
7 | "out": true // set this to false to include "out" folder in search results
8 | },
9 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts
10 | "typescript.tsc.autoDetect": "off"
11 | }
12 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | // See https://go.microsoft.com/fwlink/?LinkId=733558
2 | // for the documentation about the tasks.json format
3 | {
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "type": "npm",
8 | "script": "watch",
9 | //"problemMatcher": "$tsc",
10 | "isBackground": true,
11 | "presentation": {
12 | "reveal": "never"
13 | },
14 | "group": {
15 | "kind": "build",
16 | "isDefault": true
17 | },
18 | "problemMatcher": {
19 | "owner": "typescript",
20 | "fileLocation": "relative",
21 | "pattern": {
22 | "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$",
23 | "file": 1,
24 | "location": 2,
25 | "severity": 3,
26 | "code": 4,
27 | "message": 5
28 | },
29 | "background": {
30 | "activeOnStart": true,
31 | "beginsPattern": "^.*Starting compilation in watch mode.*$",
32 | "endsPattern": "^.*Found 0 errors. Watching for file changes.*$"
33 | }
34 | }
35 | }
36 | ]
37 | }
38 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright © 2018 Rune Mehlsen runemehlsen@gmail.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
10 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/copy-to-built.js:
--------------------------------------------------------------------------------
1 | const { copy, mkdirp, writeFile } = require("fs-extra");
2 |
3 | /**
4 | * Copy files into the ./built directory.
5 | *
6 | * This is the directory that actually has the final filesystem layout for
7 | * the extension, and to keep the vsix file small we want to only include
8 | * those files that are needed.
9 | *
10 | * Note that ./built/bundle.js is generated directly by esbuild.script.js and
11 | * not copied by this script.
12 | */
13 | async function main() {
14 | // We don't bundle the typescript compiler into ./built/bundle.js, so we need
15 | // a copy of it.
16 | await mkdirp("./node_modules/typescript/lib");
17 | await copy("./node_modules/typescript/package.json", "./built/node_modules/typescript/package.json");
18 | await copy("./node_modules/typescript/lib/typescript.js", "./built/node_modules/typescript/lib/typescript.js");
19 | await copy("./node_modules/typescript/lib/tsserverlibrary.js", "./built/node_modules/typescript/lib/tsserverlibrary.js");
20 |
21 | // For the TS compiler plugin, it must be in node modules because that's
22 | // hard coded by the TS compiler's custom module resolution logic.
23 | await mkdirp("./built/node_modules/ts-lit-plugin");
24 | const tsPluginPackageJson = require("../ts-lit-plugin/package.json");
25 | // We're only using the bundled version, so the plugin doesn't need any
26 | // dependencies.
27 | tsPluginPackageJson.dependencies = {};
28 | await writeFile("./built/node_modules/ts-lit-plugin/package.json", JSON.stringify(tsPluginPackageJson, null, 2));
29 | await copy("../ts-lit-plugin/index.js", "./built/node_modules/ts-lit-plugin/index.js");
30 |
31 | const pluginPackageJson = require("./package.json");
32 | // vsce is _very_ picky about the directories in node_modules matching the
33 | // extension's package.json, so we need an entry for ts-lit-plugin or it
34 | // will think that it's extraneous.
35 | pluginPackageJson.dependencies["ts-lit-plugin"] = "*";
36 | await writeFile("./built/package.json", JSON.stringify(pluginPackageJson, null, 2));
37 |
38 | // Copy static files used by the extension.
39 | await copy("./LICENSE.md", "./built/LICENSE.md");
40 | await copy("./README.md", "./built/README.md");
41 | await copy("./docs", "./built/docs");
42 | await copy("./syntaxes", "./built/syntaxes");
43 | await copy("./schemas", "./built/schemas");
44 | }
45 |
46 | main().catch(e => {
47 | // eslint-disable-next-line no-console
48 | console.error(e);
49 | process.exitCode = 1;
50 | });
51 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/docs/assets/lit-plugin.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/runem/lit-analyzer/b0e79a9b369dd48203e846e7c2796c8aa0a371dd/packages/vscode-lit-plugin/docs/assets/lit-plugin.gif
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/docs/assets/lit-plugin@128w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/runem/lit-analyzer/b0e79a9b369dd48203e846e7c2796c8aa0a371dd/packages/vscode-lit-plugin/docs/assets/lit-plugin@128w.png
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/docs/assets/lit-plugin@256w.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/runem/lit-analyzer/b0e79a9b369dd48203e846e7c2796c8aa0a371dd/packages/vscode-lit-plugin/docs/assets/lit-plugin@256w.png
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/esbuild.script.mjs:
--------------------------------------------------------------------------------
1 | import * as esbuild from "esbuild";
2 |
3 | await esbuild.build({
4 | entryPoints: ["src/extension.ts"],
5 | bundle: true,
6 | outfile: "built/bundle.js",
7 | platform: "node",
8 | minify: true,
9 | target: "es2017",
10 | format: "cjs",
11 | color: true,
12 | external: ["vscode", "typescript"],
13 | mainFields: ["module", "main"]
14 | });
15 |
16 | await esbuild.build({
17 | entryPoints: ["../ts-lit-plugin/src/index.ts"],
18 | bundle: true,
19 | outfile: "built/node_modules/ts-lit-plugin/lib/index.js",
20 | platform: "node",
21 | external: ["typescript"],
22 | minify: true,
23 | target: "es2017",
24 | format: "cjs",
25 | color: true,
26 | mainFields: ["module", "main"]
27 | });
28 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme.blueprint.md:
--------------------------------------------------------------------------------
1 | {{ load:./readme/header.md }}
2 |
3 | {{ load:./readme/install.md }}
4 | {{ load:./../../docs/readme/rules.md }}
5 | {{ load:./readme/config.md }}
6 | {{ load:./readme/other.md }}
7 | {{ load:./../../docs/readme/jsdoc.md }}
8 | {{ load:./readme/feature-comparison.md }}
9 | {{ load:./readme/how.md }}
10 |
11 | {{ template:contributors }}
12 | {{ template:license }}
13 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "logo": {
3 | "src": "https://user-images.githubusercontent.com/5372940/62078619-4d436880-b24d-11e9-92e0-5fcc43635b7c.png",
4 | "width": 200
5 | },
6 | "line": "rainbow",
7 | "badges": [
8 | {
9 | "alt": "Published at vscode marketplace",
10 | "url": "https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin",
11 | "img": "https://vsmarketplacebadge.apphb.com/version/runem.lit-plugin.svg"
12 | },
13 | {
14 | "alt": "Downloads per Month",
15 | "img": "https://vsmarketplacebadge.apphb.com/downloads-short/runem.lit-plugin.svg?label=vscode-lit-plugin",
16 | "url": "https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme/config.md:
--------------------------------------------------------------------------------
1 | ## Configuration
2 |
3 | You can configure this plugin by going to `VS Code Settings` > `Extension` > `lit-plugin`.
4 |
5 | **Note:** You can also configure the plugin using a `tsconfig.json` file (see [ts-lit-plugin](https://github.com/runem/lit-analyzer/blob/master/packages/ts-lit-plugin)).
6 |
7 | ### Available options
8 |
9 | {{ load:./../../docs/readme/config-table.md }}
10 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme/feature-comparison.md:
--------------------------------------------------------------------------------
1 | ## Feature comparison
2 |
3 | This plugin is similar to [vscode-lit-html](https://github.com/mjbvz/vscode-lit-html) on many points. The power of `vscode-lit-html` is that it covers all the basic functionality of HTML in tagged templates, so it's a plugin that can be easily used with other libraries than `lit-html`. However `vscode-lit-plugin` (this one) aims to be a specialized plugin for working with `lit-element / lit-html`, so for example it supports `css` and discovers web components out of the box.
4 |
5 | Below is a comparison table of the two plugins:
6 |
7 |
8 | | Feature | [vscode-lit-html](https://github.com/mjbvz/vscode-lit-html) | [vscode-lit-plugin](https://github.com/runem/vscode-lit-plugin) |
9 | |-------------------------|------------|------------|
10 | | CSS support | ❌ | ✅ |
11 | | Goto definition | ❌ | ✅ |
12 | | Check missing imports | ❌ | ✅ |
13 | | Auto discover web components | ❌ | ✅ |
14 | | Template type checking | ❌ | ✅ |
15 | | Report unknown tag names | ❌ | ✅ |
16 | | Report unknown attrs | ❌ | ✅ |
17 | | Report unknown props | ❌ | ✅ |
18 | | Report unknown events | ❌ | ✅ |
19 | | Report unknown slots | ❌ | ✅ |
20 | | Support for vscode custom data format | ❌| ✅ |
21 | | Refactor tag names | ❌ | ✅ |
22 | | Refactor attr names | ❌ | ❌ |
23 | | Auto close tags | ✅ | ✅ |
24 | | Syntax Highlighting | ✅ | ✅ |
25 | | Completions | ✅ | ✅ |
26 | | Quick info on hover | ✅ | ✅ |
27 | | Code folding | ✅ | ⚠️ (disabled until problem with calling 'program.getSourceFile' is fixed) |
28 | | Formatting | ✅ | ⚠️ (disabled until problem with nested templates is fixed) |
29 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme/header.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ template:logo }}
4 |
5 | {{ template:description }}
6 |
7 | [](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin)
8 | [](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin)
9 | [](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin)
10 |

11 |

12 |

13 |
14 |

15 |
16 |
17 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme/how.md:
--------------------------------------------------------------------------------
1 | ## How does this plugin work?
2 |
3 | All features are provided by these three libraries:
4 |
5 | - **[ts-lit-plugin](https://github.com/runem/lit-analyzer)**: The typescript plugin that powers the logic through the typescript language service (code completion, type checking, eg.). Therefore issues regarding anything but syntax highlighting should be opened in `ts-lit-plugin` and not `vscode-lit-plugin`.
6 | - **[vscode-lit-html](https://github.com/mjbvz/vscode-lit-html)**: Provides highlighting for the html template tag.
7 | - **[vscode-styled-components](https://github.com/styled-components/vscode-styled-components)**: Provides highlighting for the css template tag.
8 |
9 | This library couples it all together and synchronizes relevant settings between vscode and `ts-lit-plugin`.
10 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/readme/install.md:
--------------------------------------------------------------------------------
1 | ## Installation
2 |
3 | Simply search for [lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin) in the vscode marketplace and install the extension.
4 |
5 | **Note**: You can also run `code --install-extension runem.lit-plugin` to install it.
6 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/src/test/fixtures/completions.ts:
--------------------------------------------------------------------------------
1 | // Pretending this is the Lit html function
2 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
3 | declare const html: any;
4 |
5 | /** An element to test autocomplete with. */
6 | class CompleteMe extends HTMLElement {
7 | /** Docs for prop 1. */
8 | prop1 = "";
9 | /** Docs for prop 2. */
10 | prop2 = "";
11 | /** Docs for prop 3. */
12 | prop3 = "";
13 | }
14 | customElements.define("complete-me", CompleteMe);
15 | declare global {
16 | interface HTMLElementTagNameMap {
17 | "complete-me": CompleteMe;
18 | }
19 | }
20 |
21 | // These lines are used as a basis for testing completions, with hardcoded
22 | // line and character offsets in the test file. So if you change this file,
23 | // you'll likely need to update those offsets in ../simple-test.ts
24 | html`
25 |
28 | `;
8 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/src/test/fixtures/my-defined-element.ts:
--------------------------------------------------------------------------------
1 | export class MyDefinedElement extends HTMLElement {}
2 |
3 | customElements.define("my-defined-element", MyDefinedElement);
4 |
5 | declare global {
6 | interface HTMLElementTagNameMap {
7 | "my-defined-element": MyDefinedElement;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/src/test/fixtures/my-other-element.ts:
--------------------------------------------------------------------------------
1 | export class MyOtherElement extends HTMLElement {}
2 |
3 | customElements.define("my-other-element", MyOtherElement);
4 |
5 | declare global {
6 | interface HTMLElementTagNameMap {
7 | "my-other-element": MyOtherElement;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/src/test/fixtures/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "noEmit": true
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/src/test/scripts/mocha-driver.ts:
--------------------------------------------------------------------------------
1 | import * as path from "path";
2 | import Mocha from "mocha";
3 | import glob from "glob";
4 |
5 | /**
6 | * Runs all tests in src/test that are named like *-test.ts with Mocha.
7 | *
8 | * Called by @vscode/test-electron's runTests function in ./test-runner
9 | *
10 | * Should resolve if the tests pass, reject if any fail.
11 | */
12 | export async function run(): Promise {
13 | const mocha = new Mocha({
14 | ui: "tdd",
15 | color: true,
16 | timeout: 60_000
17 | });
18 |
19 | const testsRoot = path.join(__dirname, "..");
20 | const files = glob.sync("**/*-test.js", { cwd: testsRoot });
21 | for (const file of files) {
22 | mocha.addFile(path.resolve(testsRoot, file));
23 | }
24 | const failures = await new Promise(resolve => {
25 | mocha.run(num => resolve(num));
26 | });
27 | if (failures > 0) {
28 | throw new Error(`${failures} tests failed.`);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/src/test/scripts/test-runner.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // A script that launches vscode with our extension installed and
4 | // executes ./mocha-driver
5 |
6 | import * as path from "path";
7 |
8 | import { runTests } from "@vscode/test-electron";
9 |
10 | async function main() {
11 | try {
12 | if (process.argv.length !== 3) {
13 | throw new Error(`Usage: node ${process.argv[1]} `);
14 | }
15 | // When testing the packaged-and-then-unzipped extension, we'll be handed the path to it.
16 | const extensionPath = path.resolve(process.argv[2]);
17 | const extensionTestsPath = path.resolve(__dirname, "./mocha-driver");
18 |
19 | const fixturesDir = path.join(__dirname, "..", "..", "..", "src", "test", "fixtures");
20 | // Download VS Code, unzip it and run the integration test
21 | await runTests({ extensionDevelopmentPath: extensionPath, extensionTestsPath, launchArgs: [fixturesDir] });
22 |
23 | const inCI = !!process.env.CI;
24 | // For reasons unknown, the test runner sometimes fails to free some
25 | // resource after testing is done when running locally.
26 | // Note that at this point, the test has completed successfully.
27 | if (!inCI) {
28 | setTimeout(function () {
29 | // eslint-disable-next-line no-console
30 | console.log(`[tests completed successfully, but some resource leak is preventing the test runner from exiting, so manually exiting]`);
31 | process.exit(0);
32 | }, 1_000).unref();
33 | }
34 | } catch (err) {
35 | // eslint-disable-next-line no-console
36 | console.error(err);
37 | process.exit(1);
38 | }
39 | }
40 |
41 | main();
42 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-lit-html/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) Microsoft Corporation
2 |
3 | All rights reserved.
4 |
5 | MIT License
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
8 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
9 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
15 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
16 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
17 | OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-lit-html/README.md:
--------------------------------------------------------------------------------
1 | These JSON files are vendored in from https://github.com/mjbvz/vscode-lit-html/tree/5688ed883c4d5bf36888ae06e4e72a1c2a79d18a/syntaxes and are licensed under the license in ./LICENSE
2 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-lit-html/lit-html-string-injection.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileTypes": [],
3 | "injectionSelector": "L:meta.embedded.block.html meta.tag",
4 | "patterns": [
5 | {
6 | "include": "source.ts#template-substitution-element"
7 | }
8 | ],
9 | "scopeName": "inline.lit-html.string.injection"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-lit-html/lit-html-style-injection.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileTypes": [],
3 | "injectionSelector": "L:meta.embedded.block.html meta.property-value.css",
4 | "patterns": [
5 | {
6 | "include": "source.ts#template-substitution-element"
7 | }
8 | ],
9 | "scopeName": "inline.lit-html.style.injection"
10 | }
11 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-lit-html/lit-html-svg.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileTypes": [],
3 | "injectionSelector": "L:source.js -comment -(string -meta.embedded), L:source.jsx -comment -(string -meta.embedded), L:source.js.jsx -comment -(string -meta.embedded), L:source.ts -comment -(string -meta.embedded), L:source.tsx -comment -(string -meta.embedded)",
4 | "injections": {
5 | "L:source": {
6 | "patterns": [
7 | {
8 | "match": "<",
9 | "name": "invalid.illegal.bad-angle-bracket.html"
10 | }
11 | ]
12 | }
13 | },
14 | "patterns": [
15 | {
16 | "name": "string.js.taggedTemplate.svg",
17 | "contentName": "meta.embedded.block.svg",
18 | "begin": "(?x)(\\b(?:\\w+\\.)*(?:svg)\\s*)(`)",
19 | "beginCaptures": {
20 | "1": {
21 | "name": "entity.name.function.tagged-template.js"
22 | },
23 | "2": {
24 | "name": "punctuation.definition.string.template.begin.js"
25 | }
26 | },
27 |
28 | "end": "(`)",
29 | "endCaptures": {
30 | "0": {
31 | "name": "string.js"
32 | },
33 | "1": {
34 | "name": "punctuation.definition.string.template.end.js"
35 | }
36 | },
37 | "patterns": [
38 | {
39 | "include": "source.ts#template-substitution-element"
40 | },
41 | {
42 | "include": "text.xml"
43 | }
44 | ]
45 | }
46 | ],
47 | "scopeName": "inline.lit-html-svg"
48 | }
49 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-lit-html/lit-html.json:
--------------------------------------------------------------------------------
1 | {
2 | "fileTypes": [],
3 | "injectionSelector": "L:source.js -comment -(string -meta.embedded), L:source.jsx -comment -(string -meta.embedded), L:source.js.jsx -comment -(string -meta.embedded), L:source.ts -comment -(string -meta.embedded), L:source.tsx -comment -(string -meta.embedded)",
4 | "injections": {
5 | "L:source": {
6 | "patterns": [
7 | {
8 | "match": "<",
9 | "name": "invalid.illegal.bad-angle-bracket.html"
10 | }
11 | ]
12 | }
13 | },
14 | "patterns": [
15 | {
16 | "name": "string.js.taggedTemplate",
17 | "contentName": "meta.embedded.block.html",
18 | "begin": "(?x)(\\b(?:\\w+\\.)*(?:html|raw)\\s*)(`)",
19 | "beginCaptures": {
20 | "1": {
21 | "name": "entity.name.function.tagged-template.js"
22 | },
23 | "2": {
24 | "name": "punctuation.definition.string.template.begin.js"
25 | }
26 | },
27 | "end": "(`)",
28 | "endCaptures": {
29 | "0": {
30 | "name": "string.js"
31 | },
32 | "1": {
33 | "name": "punctuation.definition.string.template.end.js"
34 | }
35 | },
36 | "patterns": [
37 | {
38 | "include": "source.ts#template-substitution-element"
39 | },
40 | {
41 | "include": "text.html.basic"
42 | }
43 | ]
44 | }
45 | ],
46 | "scopeName": "inline.lit-html"
47 | }
48 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-styled-components/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2016 Graham Clark, Julien Poissonnier, 2018 GitHub, Tobias Zimmermann
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5 |
6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 |
8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/syntaxes/vscode-styled-components/README.md:
--------------------------------------------------------------------------------
1 | These JSON files are vendored in from https://github.com/styled-components/vscode-styled-components/tree/cfc992d93b16ddd0bc77b47c469d94e5892b2656/syntaxes
2 | and are licensed under the license in ./LICENSE
3 |
--------------------------------------------------------------------------------
/packages/vscode-lit-plugin/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "include": ["./src"],
4 | "exclude": ["node_modules", "./src/test/fixtures"],
5 | "compilerOptions": {
6 | "module": "commonjs",
7 | "target": "es6",
8 | "outDir": "out",
9 | "lib": ["es2019"],
10 | "sourceMap": true,
11 | "rootDir": "src",
12 | "tsBuildInfoFile": "./.tsbuildinfo"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | useTabs: true,
3 | tabWidth: 2,
4 | singleQuote: false,
5 | printWidth: 150,
6 | bracketSpacing: true,
7 | arrowParens: "avoid",
8 | trailingComma: "none"
9 | };
10 |
--------------------------------------------------------------------------------
/readme.blueprint.md:
--------------------------------------------------------------------------------
1 | {{ template:title }}
2 | {{ template:description }}
3 |
4 | {{ template:badges }}
5 |
6 | This mono-repository consists of the following tools:
7 |
8 | - [**`vscode-lit-plugin`**](/packages/vscode-lit-plugin) VS Code plugin that adds syntax highlighting, type checking and code completion for lit-html.
9 |
10 | - [**`ts-lit-plugin`**](/packages/ts-lit-plugin) Typescript plugin that adds type checking and code completion to lit-html templates.
11 |
12 | - [**`lit-analyzer`**](/packages/lit-analyzer) CLI that analyzes lit-html templates in your code to validate html and type check bindings.
13 |
14 | ## Rules
15 |
16 | You can find a list of all rules [here](https://github.com/runem/lit-analyzer/blob/master/docs/readme/rules.md).
17 |
18 | ## Contributing
19 |
20 | If you are interested in contributing to this repository please read [`contributing.md`](/CONTRIBUTING.md)
21 |
22 | {{ template:contributors }}
23 | {{ template:license }}
24 |
--------------------------------------------------------------------------------
/readme.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "line": "rainbow",
3 | "badges": [
4 | {
5 | "alt": "Downloads per Month",
6 | "img": "https://vsmarketplacebadge.apphb.com/downloads-short/runem.lit-plugin.svg?label=vscode-lit-plugin",
7 | "url": "https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin"
8 | },
9 | {
10 | "alt": "Downloads per Month",
11 | "img": "https://img.shields.io/npm/dm/lit-analyzer.svg?label=lit-analyzer",
12 | "url": "https://www.npmjs.com/package/lit-analyzer"
13 | },
14 | {
15 | "alt": "Downloads per Month",
16 | "img": "https://img.shields.io/npm/dm/ts-lit-plugin.svg?label=ts-lit-plugin",
17 | "url": "https://www.npmjs.com/package/ts-lit-plugin"
18 | },
19 | {
20 | "alt": "Contributors",
21 | "img": "https://img.shields.io/github/contributors/runem/lit-analyzer",
22 | "url": "https://github.com/runem/lit-analyzer/graphs/contributors"
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": ["./src"],
3 | "compilerOptions": {
4 | "target": "es5",
5 | "module": "commonjs",
6 | "lib": ["esnext"],
7 | "outDir": "./lib",
8 | "downlevelIteration": true,
9 | "strict": true,
10 | "esModuleInterop": true,
11 | "experimentalDecorators": true,
12 | "noUnusedLocals": true,
13 | "noFallthroughCasesInSwitch": true,
14 | "noImplicitThis": true,
15 | "noImplicitAny": true,
16 | "noImplicitReturns": true,
17 | "skipLibCheck": true,
18 | "declaration": true,
19 | "declarationMap": true,
20 | "incremental": true
21 | }
22 | }
23 |
--------------------------------------------------------------------------------