@fuzdev/tsv (英语)
svelte 、 TypeScript 和 CSS 的本地文件解析器, 一个 TypeScript 类型的脱衣舞女, 一个导入记录解析器( N- API)
以 Rust 为主的formatter + parser + 类型脱衣舞娘 + 导入列表器,作为Node.js和 Bun 的预建本地添加器. 跟踪的近乎成熟的物质 高级 + 键 更漂亮的插孔-丝绒 近(有记录的相差),以及一个解析器,其AST与斯维尔特的解析器+橡子+橡子型标注相兼容(并 parseCss) (中文(简体) ).
API 镜像 @fuzdev/tsv-wasm 导出用于导出 — 相同名称, 相同选项, 相同错误 — 只减去一个 WASM 引擎需要的, 而这个引擎不需要( )init, (中文(简体) ), init_sync, (中文(简体) ), wasm_module, (中文(简体) ), reinstantiate,则 ./worker 子路径和WASM IgnoreStack是因为 free() 编号 : [Symbol.dispose](),一个GC管理的本地类不需要),所以两者是倒放互换: 这个包是快速本地路径; WASM one运行于各地(包括浏览器在内),是平台的倒置而无预设约束.
文件和基准: sv.fuz.dev (英语)来源和合规说明: github.com/fuzdev/tsv (中文(简体) )。 。 。 .
安装
npm i @fuzdev/tsv
需要节点.js 22+或 Bun.
右侧平台二进制自动安装( 每个平台) optionalDependencies) (中文(简体) ). 预建的平台 :
linux-x64-gnu, (中文(简体) ),linux-arm64-gnu, (中文(简体) ),linux-x64-musl(阿尔卑斯山)darwin-arm64, (中文(简体) ),darwin-x64win32-x64
在任何其他平台上, 导入时带有指针 @fuzdev/tsv-wasm。 。 。 .
同一个本地人 tsv CLI 二进制还附着在每一个 GitHub 发布 (上方每个平台一个 SHA512SUMS 页:1 sha512sum -c每一个资产都有一份证明: gh attestation verify <file> -R fuzdev/tsv无 npm 使用.
国 际
npx @fuzdev/tsv format src # format .ts/.mts/.cts/.js/.mjs/.cjs/.svelte/.css in place, recursively
npx @fuzdev/tsv format --check . # CI: exit 1 if anything would change
npx @fuzdev/tsv format --list . # list the in-scope files, format nothing
npx @fuzdev/tsv parse file.svelte # JSON AST to stdout (--pretty to indent)
npx @fuzdev/tsv strip file.ts # TypeScript to JS on stdout, every position kept
安装( N)npm i -D @fuzdev/tsv),该桶是 tsv - 在这里它是 真实的本地CLI:平台套装 tsv的出品Rust 二进制相邻加通,而bin直接执行(esbuilt/biome形状),所以你得到当地CLI的精确合同——多文件并行主义(多文件并行主义)--jobs),平行发现,原生错误路径. (两艘二进制飞船都因为不能扮演对方的角色:一个加通不能作为进程执行,一个可执行文件不能作为进程内模块加载)
在JS/TS家族中反复出现主任.ts编号 :.mts编号 :.cts编号 :.js编号 :.mjs编号 :.cjs, (中文(简体) ), .svelte,以及 .css 有了吉提格诺发现:
- 内出一出 它的荣誉
.gitignore,则.formatignore——两相分级,相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相.prettierignore在任何没有目录中读取.formatignore(兄弟会).formatignore暗地里,有警告;所有范围都放入回放,结果可以复制. - 在回扣之外 它只荣耀
.formatignore。 。 。 . - 没有
.gitignore在范围(在或出回转)中,发现会回到跳过隐藏目录dist编号 :build编号 :target。 。 。 .node_modules而VCS目录总是被一行跳过. - 您命名的路径—— 文件或目录—— 仅以被忽略文件为界限: 被忽略的路径被跳过( 带有警告, 除非它是您的文件 )
.formatignore或者说.prettierignoreexcept)),而内置跳过则永远不会对其适用;一个被命名的文件的扩展必须仍然是一个 tsv 格式.
format --list 在不格式化的情况下打印已发现的镜像文件——只读视图 format 会触摸. --content <source> 编号 : --stdin (与 --parser svelte|typescript|css) 格式或解析字符串用于 stdout 。 对于类型脚本, --source-type script|module (单位:千美元)parse 默认为 module· ; format 以未设定的旗帜为 无名称 模块,作为脚本重审,但 .mjs编号 :.mts 路径,一个自有名的模块,不需要重试——并接受在 --content编号 :--stdin 仅)选择剖析目标——在 script, (中文(简体) ), await 是普通标识符, 顶级 import编号 :export, (中文(简体) ), for await 财务报告和审定财务报表 import.meta 错误, 代码是草率的, 除非它自己的 "use strict" 序语使其严格(所以) with 和遗物正八字/逃脱分析). parse 发射仅限跨度的线条( 无每个节点) loc; 斯维尔特也无 name_loc(三); parse --locations 加上他们。 退出代码 - format:0干净,1会改变(--check2个错误; parse: 0 解析, 1 输入不解析, 2 为用法或读取错误 .
strip 使用一个类型脚本输入 - a .ts编号 :.mts编号 :.cts 路径(a) .svelte.ts 包含 rune 模块; JavaScript 路径被拒绝而不是读取为 TypeScript ), --content,或 --stdin - 以联署材料的印出,每类空白为白色(取出类型(三); --check 没有写 stdout 只设置退出代码( 拒绝或解析错误仍然在 stderr 上说明原因) 。 分析的目标是 format's: 一个模块, 如果失败的话, 重试为脚本( a) .mts 路径不重试),或一条 --source-type script|module 名称 --content编号 :--stdin。退出代码 - strip: 0 剥去, 1 拒绝( TypeScript 该类型空白无法擦去, 例如 : enum),2 解析错误,不可读文件或使用错误.
文件格式平行; --jobs N 超过工人数。 (如果平台套件的CLI 二进制缺失或无法运行,则该套件在加通上降解为同一份合同的JS镜相类似——在工人线条上也类似;在一个完全没有预建套件的平台上,使用 @fuzdev/tsv-wasm 改为. ) 两个包裹都声称: tsv bin 名称,所以在工程中安装其中之一.
使用量
软件包是无害环境管理的,没有初始化步骤(一个通用JS主机加载它 await import('@fuzdev/tsv'):
import {format_svelte, format_typescript, parse_typescript} from '@fuzdev/tsv';
const formatted = format_svelte('<script>\nconst x=1\n</script>'); // {ok: true, code}
const parsed = parse_typescript('const x = 1;'); // {ok: true, ast}: acorn-typescript-shaped, span-only
if (!parsed.ok) throw new Error(parsed.error.message);
格式化
format_svelte 编号 : format_typescript 编号 : format_css 取一个源 string 返回时 {ok: true, code} 带有格式 string,或 {ok: false, error} 对于无法格式化的源(错误) (中文(简体) ). 格式化本身是不可配置的;唯一的选项是 TypeScript 的剖析目标, format_typescript(source, {sourceType: 'script' | 'module'})数字 :
'module'——源是模块,始终严格.'script'—— 说await是普通标识符, 顶级import编号 :export, (中文(简体) ),for await财务报告和审定财务报表import.meta是语法错误,而代码是草率的,除非它自己的"use strict"序语使其严格(所以)with和遗物正八字/逃脱分析).- 省略——与
'module':源被格式化为模块,只有在解析失败时,才会被重试为脚本. 因此,遗留的草率脚本格式完全没有选项,而模块语法所接受的任何内容都永远不会被重新解释.
设定值是精确的 。 由于没有命名,而且两个语法都拒绝来源,所以返回的错误是解释失败的最佳错误(规则在repo's) 文件/目录) (中文(简体) ). parse_typescript 没有这种倒置; 有省略 sourceType 表示 'module'。 。 。 .
分析
parse_svelte 编号 : parse_typescript 编号 : parse_css 返回时 {ok: true, ast} 以语言的公开JSON AST作为对象——默认情况下仅跨度, start编号 :end 每个节点和每个节点均抵消 loc; 数据 parse_*_json 兄弟姐妹们把电线还给JSON弦, {ok: true, json},对于不支付就转帐的消费者 JSON.parse。不解析返回的源 {ok: false, error} (单位:千美元)错误) (中文(简体) ). 对象解析器可选 {locations?, sourceType?} 包,那个 _json 这些 {sourceType?},以及 sourceType 仅是类型脚本。 AST 的脚本类型被捆绑入 tsv_ast.d.ts 并且从包件中再出口(import type {...} from '@fuzdev/tsv') (中文(简体) ).
locations: true 添加 loc (和斯维尔特的) name_loc在联合来文中 reconstruct_locations。它也导出,带有 create_locator(source, {language}) 寻找稀疏的外观( e)language (第2条) position_at(offset) 编号 : loc_of(node) 丢出一个 RangeError 用于抵消或跨度源(a) TypeError 对于一个不是数字的偏移, 或一个节点 start编号 :end 全树的花样reconstruct_locations,定位器的 reconstruct(ast))每节点检查一无所获,并取出一棵环形树——剖面自有,或取出克隆. 两者也是 @fuzdev/tsv/locations 进入点,纯洁的JS 装入没有本地加通.
取出类型
strip_typescript(source) 将TypeScript改为JS,方法是将每个类型都空白为白空间——没有变换,没有源图:每个幸存的字符都保持了行和UTF-16列,行名词词句保持了逐字记录,一个无字词源回来时没有变化. 单凭空白就让下一行继续发言 ;, (中文(简体) ), ( 或者说 ) 代替一个空白的角色.
它返回一个结果,而不是放弃它在来源中发现的东西: {ok: true, code},或 {ok: false, error} 与 error.kind 'parse' (错误 a) parse_typescript 源返回到该错误所属目标)或 'unsupported' (字节脚本,该类型空白不能去除——a) enum,一个值 namespace,参数属性, import =, (中文(简体) ), export =, (中文(简体) ), <T>x,或一个 as 编号 : satisfies 其删除将重新组合其表达式——由 error.construct,其跨度为 start编号 :end 财务报告和审定财务报表 loc,单行 message,则a frame 与线和护身符.
import {strip_typescript} from '@fuzdev/tsv';
const result = strip_typescript('let id: string = "a";\nenum Color { Red }\n');
if (!result.ok && result.error.kind === 'unsupported') {
result.error.construct; // 'enum'
result.error.loc.start; // {line: 2, column: 0}
}
一个选择是 sourceType,读作 format_typescript 读取:省略了,如果失败,源是一个模块重试为脚本,所以遗留的草率脚本会像草率脚本一样被剥去; 'script' 或者说 'module' 没错.
列出进口品
parse_imports_typescript(source) 财务报告和审定财务报表 parse_imports_svelte(source) 列出源模块请求——每个静态 import,再出口,动态 import(…) 财务报告和审定财务报表 import x = require(…),按来源顺序——不给你AST: {ok: true, hasModuleSyntax, imports},或 {ok: false, error} 对于一个不解析的来源。 每个记录是 {kind, start, end, specifier, typeOnly, phase, attributes} —— 说 kind 'static' 编号 : 're_export' 编号 : 'dynamic' 编号 : 'import_equals', (中文(简体) ), specifier {value, start, end} (解码字符串,其间距引号被排除)或 null 计算 import(x), (中文(简体) ), typeOnly 'statement' 编号 : 'specifiers' 编号 : null, (中文(简体) ), phase 'source' 编号 : 'defer' 编号 : null, (中文(简体) ), attributes (单位:千美元) {start, end} 间距或 null 页:1 @fuzdev/tsv-wasm 返回.
import {parse_imports_svelte} from '@fuzdev/tsv';
const result = parse_imports_svelte('<script>\n\timport Button from "./Button.svelte";\n</script>\n');
if (result.ok) {
result.imports[0]?.specifier?.value; // './Button.svelte'
result.hasModuleSyntax; // true
}
parse_imports_typescript 带 sourceType,读作 strip_typescript 读取; parse_imports_svelte 没有.
选项
选项表现为 @fuzdev/tsv-wasm: 支持的密钥集为 undefined 读取为默认,a sourceType- 仅向任何函数发送袋 (sourceType: undefined 列入Svelte和CSS;a locations 键,不管其值如何,除对象解析器外,在任何地方抛出。 参数错误被抛出 TypeError编号:
- 未知的密钥,不论价值如何;
- a. 类型错误或无效的值,或不是字符串或形状不完善的UTF-16源(它持有一个单独代位);
- 一个非对象的第二个参数, 包括数组—— 写入
sources.map((s) => format_typescript(s))没有sources.map(format_typescript),通过索引.
文件范围
IgnoreStack 是tsv自己的等级性,有信仰的相配者 再加上它的发现政策(classify_dir, (中文(简体) ), should_format_file, (中文(简体) ), is_path_pruned, (中文(简体) ), path_shadow_warning, (中文(简体) ), excluded_argument_warning, (中文(简体) ), unsupported_extension_error,以及警告模板),导出后,工具可以复制准确的文件 tsv format 会触摸——同一类人 @fuzdev/tsv-wasm 出口; @fuzdev/tsv-format-wasm 以实例记录。 两种答案每一次其申报类型都承认相同;与外表功能不同的是,类在每一个引擎自己的约束层中检查其论据,因此错误类型的论据被每个引擎拒绝或强制不同.
错误
不解析返回的源 {ok: false, error} 从一个解剖器,一个前题 和条状物,同样的结果 @fuzdev/tsv-wasm 返回 - 与 error 普通对象(无堆栈; postMessage-可以吗 {kind: 'parse', message, frame, start, end, loc}键入 TsvParseError (出口),在与AST自身位置相同的坐标:
message说出了什么问题,在一条线上;frame是其中的节选——aline:column头和源线,然后是护栏线——所以`${message}\n${frame}`是 CLI 打印的文本.start财务报告和审定财务报表end是错误的 UTF-16 偏移 —— 分析错误是一个点, 所以end === start- 和loc是他们的{start: {line, column}, end: {line, column}}(以一行为主,以0为主的UTF-16列),形状为节点:create_locator(source, {language}).loc_of(result.error)等同着.- TypeScript计算了ECMAScript行终止符(LF, CR, CRLF, U+2028, U+2029)和一个领先的 BOM; Svelte (
<script>, (中文(简体) ),<style>和模板表达式)和CSS单独计算LF,并留下一个领先的BOM. - 框头是
loc.start作为line:column + 1。 。 。 . - 包含 CRLF 线段结尾所在的您自有的源文件报告位置 —— 解析器报告错误( 它)
message如果引用源文本,则可以不同,如果引用源文本,则前题读取时会以行尾折叠为LF),除非没有sourceType, (中文(简体) ),format_typescript可报告其脚本重试错误.
import {format_typescript} from '@fuzdev/tsv';
const result = format_typescript('let a;\nconst = ;');
if (!result.ok) {
result.error.kind; // 'parse'
result.error.message; // "Expected identifier or destructuring pattern, found '='"
result.error.frame; // '2:7 const = ;\n ^ here'
[result.error.start, result.error.loc.start]; // [13, {line: 2, column: 6}]
}
format_svelte 拒绝一个可以解析的源: 单个 CR( 不是 CRLF 的一部分) , 其后有注释文本 // 在标签属性之间注释, Svelte 仅以 LF 结尾 —— formatter 的 CR- to- LF 折叠会提早结束该注释, 并将其行的其余部分变为标记 。 拒绝是 {kind: 'refused', message, frame, start, end, loc} (类型) FormatRefusedError),其跨度为CR.
仍然投出的结果是无法报告:一个参数错误(a) TypeError,上面),一个超过4个GiB尺寸盖的源,以及下面的引擎故障.
Rust恐慌——总是个tsvbug,请报告——也被扔出,而不是中止进程;堆积溢出是一个仍然可以中止的崩溃,因为是赤裸裸的 SIGSEGV,而 tsv 的深度限制使其无法达到:一个源被嵌入或被锁入的源被拒绝作为普通的剖析出错(s{ok: false, error}) ——计出地平线将添加的参数,所以它再次接受参数的任何来源的输出——以及它们下的每一输入都符合2个米B线程——按每个形状分出其最深被接受深度的极限数(极限和堆栈合同在repo's) 文件/目录) (中文(简体) ). 主线程(进程堆栈限制,通常为8 MiB)和 a worker_threads 工人(Node's 4 MiB 默认值)都持有;只有从你开始的工人 resourceLimits.stackSizeMb 2以下为合同规定。 捆绑 tsv CLI 大小自有堆栈. 重建 loc —— 说 {locations: true},或 reconstruct_locations ——在联署材料中运行,不重复,因此其深度与剖面一样.
状态
格式化器已接近生产准备. 长尾的稀有昆虫残骸和API仍然可能改变;报告受到赞赏.
许可证
0BSD AND BSD-3-Clause: tsv 自己的代码是 0BSD 数据,而编译的WhatWG命名字符参考表是 BSD-3-Clause ——参见 通知这包里装的是什么.