sveast 0.9.5 → 0.9.7
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/README.md +49 -4
- package/a11y.d.ts +1636 -0
- package/a11y.js +36 -0
- package/core.js +1 -1
- package/index.d.ts +39 -7
- package/index.js +1 -1
- package/is-valid-type.js +1 -1
- package/lexer.d.ts +39 -7
- package/lexer.js +2 -2
- package/module.js +1 -1
- package/package.json +6 -1
- package/parse-imports-exports.js +1 -1
- package/parse-module.js +1 -1
- package/parse-sections.js +1 -1
- package/parse.js +1 -1
- package/runes.js +1 -1
- package/{shared-rce4ty8a.js → shared-a23q4q40.js} +1 -1
- package/shared-dscc5xg8.js +2 -0
- package/shared-e4gbs4rb.js +3 -0
- package/{shared-cs1ezg1f.js → shared-f45stvzk.js} +1 -1
- package/{shared-rvkvagj5.js → shared-k0xcpcmz.js} +1 -1
- package/{shared-qkp49nav.js → shared-nb0h4j83.js} +1 -1
- package/{shared-xwzsb4m8.js → shared-qqrqzz29.js} +1 -1
- package/shared-s46wfvhw.js +10 -0
- package/{shared-nan648gn.js → shared-w3mxqtgj.js} +1 -1
- package/{shared-z9y4mrek.js → shared-x2vs5571.js} +1 -1
- package/{shared-y41kz9tv.js → shared-xmc2pnaf.js} +1 -1
- package/typescript.js +1 -1
- package/shared-2pngd0mg.js +0 -10
- package/shared-ke0fgd3r.js +0 -2
- package/shared-y3nf00py.js +0 -3
package/README.md
CHANGED
|
@@ -25,7 +25,8 @@ ast.fragment.nodes; // [Text, RegularElement]
|
|
|
25
25
|
| [`parseSections`](#parsesectionssource-options--astroot) | A component's AST without the markup: its `<script>`s, `<style>` and `<svelte:options>` | `sveast` |
|
|
26
26
|
| [`parseModule`](#parsemodulesource-options--program) | A `.js` or `.ts` module's AST, the same as a component's `<script>` | `sveast` |
|
|
27
27
|
| [`parseImportsExports`](#parseimportsexportssource-options--moduledeclaration) | A module's `import` and `export` statements, without parsing the rest | `sveast` |
|
|
28
|
-
| [`lexImportsExports`](#leximportsexportssource--lexedstatement) | Their offsets, sources and names, without loading a parser | `sveast/lexer` |
|
|
28
|
+
| [`lexImportsExports`](#leximportsexportssource-options--lexedstatement) | Their offsets, sources and names, without loading a parser | `sveast/lexer` |
|
|
29
|
+
| [`lexDynamicImports`](#lexdynamicimportssource--lexeddynamicimport) | A module's `import(…)`, `require(…)` and `import.meta.glob(…)`, with their offsets and sources, without loading a parser | `sveast/lexer` |
|
|
29
30
|
| [`lexComponent`](#lexcomponentsource--lexedcomponent) | A component's `<script>`s, `<style>` and `<svelte:options>`, with their attributes and offsets, without loading a parser | `sveast/lexer` |
|
|
30
31
|
| [`lexStrings`](#lexstringssource--lexedstring) | A module's string and template literals, with their offsets and values, without loading a parser | `sveast/lexer` |
|
|
31
32
|
| [`createParser`, `createModuleParser`](#smaller-bundles-sveastcore-and-sveastmodule) | The parsers without TypeScript, named HTML entities or the template parser, for a smaller bundle | `sveast/core`, `sveast/module` |
|
|
@@ -35,6 +36,7 @@ ast.fragment.nodes; // [Text, RegularElement]
|
|
|
35
36
|
| [`children`, `forEachChild`](#childrennode-keys--node-and-foreachchildnode-callback-keys--void) | A node's children, cached or without allocating | `sveast`, `sveast/walk` |
|
|
36
37
|
| [`isReference`](#isreferencenode-parent--boolean), [`extractIdentifiers`](#extractidentifierspattern--identifier) | Which identifiers are references, and which ones a pattern declares | `sveast`, `sveast/walk` |
|
|
37
38
|
| [`analyzeScopes`](#analyzescopesast--scopes) | Which declaration each name refers to, and every read and write of it | `sveast`, `sveast/scope` |
|
|
39
|
+
| [`a11yWarnings`](#a11ywarningsast-options--a11ywarning) | svelte's accessibility warnings, without compiling | `sveast/a11y` |
|
|
38
40
|
| [`createLocator`, `locate`](#createlocatorsource--offset--position) | Lines and columns for the nodes you report, without parsing with `loc` | `sveast`, `sveast/walk` |
|
|
39
41
|
|
|
40
42
|
## Migrating from svelte/compiler
|
|
@@ -145,7 +147,7 @@ Parses a JavaScript or TypeScript module, such as a `.ts` file a component impor
|
|
|
145
147
|
|
|
146
148
|
### `parseImportsExports(source, options?) => ModuleDeclaration[]`
|
|
147
149
|
|
|
148
|
-
A module's top-level `import` and `export` statements, without parsing the rest, e.g. to rewrite a component's imports or follow a module graph. Each node is the one `parseModule(source, { comments: false })` has for that statement: `ImportDeclaration`, `ExportNamedDeclaration`, `ExportDefaultDeclaration` and `ExportAllDeclaration`, and, in TypeScript, `TSImportEqualsDeclaration`, `TSExportAssignment` and `TSNamespaceExportDeclaration`. `import(...)` and `import.meta` are expressions, so they aren't returned. Unlike a regex, it never matches an `import` in a comment, a string, a template or a nested block such as `declare module "a" { ... }`.
|
|
150
|
+
A module's top-level `import` and `export` statements, without parsing the rest, e.g. to rewrite a component's imports or follow a module graph. Each node is the one `parseModule(source, { comments: false })` has for that statement: `ImportDeclaration`, `ExportNamedDeclaration`, `ExportDefaultDeclaration` and `ExportAllDeclaration`, and, in TypeScript, `TSImportEqualsDeclaration`, `TSExportAssignment` and `TSNamespaceExportDeclaration`. `import(...)` and `import.meta` are expressions, so they aren't returned; [`lexDynamicImports`](#lexdynamicimportssource--lexeddynamicimport) finds them. Unlike a regex, it never matches an `import` in a comment, a string, a template or a nested block such as `declare module "a" { ... }`.
|
|
149
151
|
|
|
150
152
|
It stops after the last `import` or `export` that could start a statement, so the code after a component's imports is never read: on Carbon's component scripts, it takes a third of `parseModule`'s time, and about a seventh with `localExports: false`. A syntax error in a statement it returns throws a `ParseError`, including a name exported twice; errors elsewhere aren't reported.
|
|
151
153
|
|
|
@@ -164,12 +166,14 @@ function dependencies(source: string, typescript = false): string[] {
|
|
|
164
166
|
}
|
|
165
167
|
```
|
|
166
168
|
|
|
167
|
-
### `lexImportsExports(source) => LexedStatement[]`
|
|
169
|
+
### `lexImportsExports(source, options?) => LexedStatement[]`
|
|
168
170
|
|
|
169
171
|
From `sveast/lexer`, and also `sveast`. A module's top-level `import` statements and `export … from` re-exports, read by hand instead of parsed, for a tool on a hot or eagerly loaded path, such as a preprocessor that rewrites a component's imports, that needs each statement's offsets, source and names, but not the AST. `sveast/lexer` loads no parser, so a fresh process imports it in 1.4 ms, and on Carbon's component scripts it takes 40% of the time `parseImportsExports` takes with `localExports: false`.
|
|
170
172
|
|
|
171
173
|
It finds the statements `parseImportsExports` returns with `localExports: false`, with the same offsets, sources and names. It doesn't check syntax and never throws: a statement it can't read, such as `import { a from "a"` or `import a = require("a")`, has `source: null` and no specifiers, and ends where it stopped reading. `import type` and `type` before a name are always read.
|
|
172
174
|
|
|
175
|
+
With `exportLists: true`, it also returns each top-level `export { a, b as c }` without `from`, e.g. to follow a binding through an `index.js` that imports it and exports it again: `source` is `null`, and each specifier has kind `local`, with `local` the binding in this module. Those are the `ExportNamedDeclaration`s without a declaration that `parseImportsExports` returns with `localExports: true`; `export const a`, `export function b` and `export default` still aren't returned. A module that ends with an export list is read to its end.
|
|
176
|
+
|
|
173
177
|
```ts
|
|
174
178
|
import { lexImportsExports } from "sveast/lexer";
|
|
175
179
|
|
|
@@ -181,7 +185,7 @@ for (const statement of lexImportsExports(source)) {
|
|
|
181
185
|
statement.typeOnly; // `import type …` or `export type …`
|
|
182
186
|
statement.specifiers;
|
|
183
187
|
// import: { kind: "default" | "namespace" | "named", imported, local, typeOnly, start, end }
|
|
184
|
-
// export: { kind: "all" | "namespace" | "named", local, exported, typeOnly, start, end }
|
|
188
|
+
// export: { kind: "all" | "namespace" | "named" | "local", local, exported, typeOnly, start, end }
|
|
185
189
|
}
|
|
186
190
|
```
|
|
187
191
|
|
|
@@ -191,9 +195,29 @@ for (const statement of lexImportsExports(source)) {
|
|
|
191
195
|
| `* as a` | `namespace`, `imported: "*"`, `local: "a"` | `namespace`, `local: "*"`, `exported: "a"` |
|
|
192
196
|
| `*` | | `all`, `local: "*"`, `exported: null` |
|
|
193
197
|
| `b as c`, `"b-c" as d` | `named`, `imported: "b"`, `local: "c"` | `named`, `local: "b"`, `exported: "c"` |
|
|
198
|
+
| `b as c` in `export { … }`, with `exportLists` | | `local`, `local: "b"`, `exported: "c"` |
|
|
194
199
|
|
|
195
200
|
Names are as the module sees them: escapes decoded, and a string name without its quotes. A specifier's `typeOnly` is also `true` in an `import type` or `export type`. Its `start` is that of `type` before the name, if any, and `end` is after the last name; for `export *`, after the `*`.
|
|
196
201
|
|
|
202
|
+
### `lexDynamicImports(source) => LexedDynamicImport[]`
|
|
203
|
+
|
|
204
|
+
From `sveast/lexer`, and also `sveast`. A module's `import(…)` and `require(…)` calls and Vite's `import.meta.glob(…)`, at any depth, in source order, read without parsing, e.g. to follow the lazily loaded part of a module graph. Unlike a regular expression, it never matches in a comment, a string, a template or a regular expression, and it tells a literal argument from a computed one. `lexImportsExports` finds the static imports; together they're a module's dependencies.
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { lexDynamicImports } from "sveast/lexer";
|
|
208
|
+
|
|
209
|
+
for (const call of lexDynamicImports(source)) {
|
|
210
|
+
call.kind; // "import" | "require" | "glob"
|
|
211
|
+
call.start; // offset of `import` or `require`
|
|
212
|
+
call.end; // after the `)`
|
|
213
|
+
call.source; // { value: "./Chart.svelte", start, end } (quotes or backticks included), or null
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`source` is the first argument if it's a string or a template without `${…}` and it's followed by `)` or `,`, as in `import("a", { with: { type: "json" } })`; it's `null` for a computed argument such as `` import(`./${name}.js`) `` or `import.meta.glob(["a", "b"])`, and for a call without arguments. Type arguments are skipped, as in `import.meta.glob<Module>("./*.ts")`.
|
|
218
|
+
|
|
219
|
+
Where `parseModule` accepts the module, the calls are its `ImportExpression`s, its calls of an identifier `require`, `new require(…)` included, and of `import.meta.glob`, and in TypeScript also its `import("a")` types, as in `typeof import("a")`, and the `require("a")` of `import a = require("a")`. A method named `import` or `require`, such as `{ import() {} }`, isn't a call, and neither are `a.require(…)`, `require?.(…)` or `(require)(…)`. It doesn't check syntax and never throws. It matched `parseModule` on all 33,001 modules and component scripts it accepts from the projects under [Parity and performance](#parity-and-performance), svelte's tests and TypeScript's conformance tests.
|
|
220
|
+
|
|
197
221
|
### `lexComponent(source) => LexedComponent`
|
|
198
222
|
|
|
199
223
|
From `sveast/lexer`, and also `sveast`. A component's top-level `<script>`, `<script module>`, `<style>` and `<svelte:options>`, with their attributes and the offsets of their tags and content, found without parsing: e.g. to read a component's scripts and their imports, its language or its options, or to rewrite a script, on a path that can't afford a parser. On the benchmark corpus it's about 50× faster than `parse`.
|
|
@@ -405,6 +429,27 @@ The markup's scopes are svelte's:
|
|
|
405
429
|
|
|
406
430
|
Names in TypeScript's types aren't references, and `type` and `interface` declare nothing; it skips them with `valueVisitorKeys`. Enums, enum members and namespaces are declared. It doesn't change the AST, and takes less than half as long as parsing it.
|
|
407
431
|
|
|
432
|
+
### `a11yWarnings(ast, options?) => A11yWarning[]`
|
|
433
|
+
|
|
434
|
+
From `sveast/a11y`. The `a11y_…` warnings svelte's compiler gives for a component, with the same `code`, `message` and offsets, and without the ones a `<!-- svelte-ignore -->` comment before an element, or one of its ancestors, silences. For a linter that already has the AST: on Carbon's 2,202 components it takes 60 ms, against 735 ms for `compile(source, { generate: false })`. It loads neither acorn nor the parser.
|
|
435
|
+
|
|
436
|
+
| Option | Default | Description |
|
|
437
|
+
|:---|:---|:---|
|
|
438
|
+
| `runes` | `false` | Whether the component compiles in runes mode, as [`isRunesMode`](#isrunesmodesource--boolean) says. In runes mode, `svelte-ignore` takes only svelte 5's codes, separated by commas; in legacy mode, svelte 4's `a11y-…` codes too, as svelte does. |
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
import { isRunesMode, parse } from "sveast";
|
|
442
|
+
import { a11yWarnings } from "sveast/a11y";
|
|
443
|
+
|
|
444
|
+
for (const warning of a11yWarnings(parse(source), { runes: isRunesMode(source) })) {
|
|
445
|
+
warning.code; // "a11y_missing_attribute"
|
|
446
|
+
warning.message; // "`<img>` element should have an alt attribute\nhttps://svelte.dev/e/a11y_missing_attribute"
|
|
447
|
+
warning.start; // offsets of the element or attribute
|
|
448
|
+
}
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The ARIA tables come from svelte's, which read aria-query and axobject-query, generated into the package, so it has no dependencies. On svelte's tests, carbon-components-svelte, bits-ui, shadcn-svelte, skeleton, flowbite-svelte, svelte.dev, immich and SvelteKit, it gives the warnings `compile` gives for all 13,276 components both accept, 899 warnings, and for 13,163 with their `svelte-ignore` comments and common a11y attributes removed, 2,185 warnings.
|
|
452
|
+
|
|
408
453
|
### `createLocator(source) => (offset) => Position`
|
|
409
454
|
|
|
410
455
|
A function from an offset to its `{ line, column }`, line from 1 and column from 0, as `loc: true` gives them: for a tool that parses without `loc`, which is faster, and needs lines only for what it reports. Lines are found on the first call, and each lookup starts its search at the line found last, so lookups in source order are fastest. Lines end at `\n`, as in the markup's `loc` and `ParseError`; acorn's `loc` in scripts and modules also ends them at a lone `\r`, U+2028 and U+2029. `parse` drops a leading byte order mark, so pass the source without one.
|