@tslite/explain 0.2.0

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/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ 'use strict';var core=require('@tslite/core'),printer=require('@tslite/printer'),operators=require('@tslite/operators');var i="checker D9 / docs/SCOPE-BOUNDARY.md";function h(e,t){let n=T(e);return t.diagnostics.map(s=>{let o=u(s,n);return o?{...s,help:o}:s})}function u(e,t){let n=e.node;switch(n.type){case "NewExpression":return B(n);case "ClassDeclaration":case "ClassExpression":return k();case "FunctionDeclaration":case "FunctionExpression":return O();case "ThisExpression":return E();case "MemberExpression":return e.code==="forbidden-member"?D(n):x(e,n,t)}}function x(e,t,n){if(e.code!=="no-such-member"&&e.code!=="not-object")return;let s=l(t);if(!s)return;let o=operators.jsMethodReplacements[s];if(o)return w(t,s,o,n);if(operators.knownProtoMembersWithoutOperator.has(s))return N(s)}function w(e,t,n,s){let o=printer.print(e.object),a=s.get(e),c=a?.type==="CallExpression"&&a.callee===e,d=c?a.arguments.map(m=>printer.print(m)):[],p=n.call(o,d),g=printer.print(c?a:e);return {reason:"proto-member",category:"portability",explain:`${n.on==="array"?"Arrays":n.on==="string"?"Strings":"Values"} in TSL have no \`.${t}\` method (prototype member). TSL is FP-first and PORTABLE: \`.${t}\` does not translate cleanly to the target (in Python, for instance, it is a function). This is not a language bug \u2014 it is the model.`,suggestion:`Use the \`${n.operator}\` operator (@tslite/operators): \`${p}\`.`,fix:{from:g,to:p},docs:i}}function N(e){return {reason:"proto-member",category:"portability",explain:`\`.${e}\` is a JS prototype method/property \u2014 TSL is FP-first and immutable, so array/string/object methods are not vocabulary. This is not a language bug \u2014 it is the model.`,suggestion:"Rewrite it functionally with @tslite/operators (map/filter/reduce/\u2026), or use the imperative capability if you truly need to mutate.",docs:i}}function D(e){return {reason:"forbidden-substrate",category:"js-ism",explain:`\`.${l(e)??"constructor/prototype/__proto__"}\` is JS runtime substrate (inheritance/prototype) \u2014 it does not exist in TSL, which is FP-first and portable. Forbidden by identity + portability (and it closes the sandbox escape). This is not a language bug \u2014 it is the model.`,docs:i}}function B(e){let t=e.callee,n=t?.type==="Identifier"?t.name:"X";return {reason:"no-new",category:"js-ism",explain:"TSL has no `new` and no classes \u2014 it is FP-first (no OO). `new` was removed on purpose: native capabilities come in as FACTORY functions via DI. Not a language bug.",suggestion:`Inject a factory and call \`${n.charAt(0).toLowerCase()+n.slice(1)}(\u2026)\` instead of \`new ${n}(\u2026)\`.`,docs:i}}function k(){return {reason:"no-class",category:"js-ism",explain:"`class` does not exist in TSL \u2014 it is FP-first, no OO. An instance is just an object with props; behavior comes from functions. This is not a language bug \u2014 it is the model.",suggestion:'Model with objects + functions (a factory function via DI for "methods").',docs:i}}function E(){return {reason:"no-this",category:"js-ism",explain:"`this` does not exist in TSL \u2014 no OO, no implicit receiver. This is not a language bug \u2014 it is the model.",suggestion:"Pass the data as an explicit ARGUMENT instead of `this`.",docs:i}}function O(){return {reason:"no-function-expr",category:"js-ism",explain:"Only ARROW functions are functions in TSL (`(x) => \u2026`). `function(){}` is out (it brings `this`/`arguments`/construction \u2014 OO substrate). This is not a language bug \u2014 it is the model.",suggestion:"Use an arrow: `const f = (x) => \u2026`.",docs:i}}function l(e){if(!e.computed)return e.property.name;let t=e.property;return t.type==="Literal"&&typeof t.value=="string"?t.value:void 0}function T(e){let t=new WeakMap;return core.walk(e,{"*":(n,s)=>{s&&t.set(n,s);}}),t}exports.explain=h;exports.helpFor=u;
@@ -0,0 +1,40 @@
1
+ import { BaseNode } from '@tslite/core';
2
+ import { Diagnostic, CheckResult } from '@tslite/checker';
3
+
4
+ /** Por que o erro aconteceu — a "raiz JS-ism" que o help explica. */
5
+ type JsIsmReason = "proto-member" | "no-new" | "no-class" | "no-this" | "no-function-expr" | "forbidden-substrate";
6
+ /** A CLASSE do porquê — deixa uma UI didática renderizar diferente de erro de tipo. */
7
+ type HelpCategory = "js-ism" | "portability" | "capability-off";
8
+ /** O help auxiliar: prosa explicativa + sugestão + auto-fix aplicável (por IA/editor).
9
+ * A prosa (`explain`/`suggestion`) é o DEFAULT em inglês (convenção da casa, como as
10
+ * mensagens do checker). `reason` é a CHAVE estável de tradução: um add-on de i18n no
11
+ * frontend mapeia `reason` (+ os campos estruturados) → idioma, sem tocar isto. */
12
+ interface DiagnosticHelp {
13
+ readonly reason: JsIsmReason;
14
+ readonly category: HelpCategory;
15
+ /** "Why this is NOT a language bug" — default prose (English). */
16
+ readonly explain: string;
17
+ /** The correct idiom (e.g. "Use the `length(xs)` operator"). */
18
+ readonly suggestion?: string;
19
+ /** Reescrita mecânica: `from` → `to` (aplicável por code-action ou por uma IA). */
20
+ readonly fix?: {
21
+ readonly from: string;
22
+ readonly to: string;
23
+ };
24
+ /** Âncora de documentação. */
25
+ readonly docs?: string;
26
+ }
27
+ /** Um diagnóstico do checker, possivelmente enriquecido com `help` (aditivo). */
28
+ type ExplainedDiagnostic = Diagnostic & {
29
+ readonly help?: DiagnosticHelp;
30
+ };
31
+ /**
32
+ * Enriquece os diagnósticos de um `CheckResult` com `help` onde o erro é um JS-ism
33
+ * reconhecível. `ast` é a MESMA raiz que foi checada (pra achar pais/nós). Os
34
+ * diagnósticos sem JS-ism reconhecido passam intactos.
35
+ */
36
+ declare function explain(ast: BaseNode, result: CheckResult): ExplainedDiagnostic[];
37
+ /** O `help` de um diagnóstico isolado, dado o mapa de pais (ou `undefined`). */
38
+ declare function helpFor(d: Diagnostic, parents: WeakMap<BaseNode, BaseNode>): DiagnosticHelp | undefined;
39
+
40
+ export { type DiagnosticHelp, type ExplainedDiagnostic, type HelpCategory, type JsIsmReason, explain, helpFor };
@@ -0,0 +1,40 @@
1
+ import { BaseNode } from '@tslite/core';
2
+ import { Diagnostic, CheckResult } from '@tslite/checker';
3
+
4
+ /** Por que o erro aconteceu — a "raiz JS-ism" que o help explica. */
5
+ type JsIsmReason = "proto-member" | "no-new" | "no-class" | "no-this" | "no-function-expr" | "forbidden-substrate";
6
+ /** A CLASSE do porquê — deixa uma UI didática renderizar diferente de erro de tipo. */
7
+ type HelpCategory = "js-ism" | "portability" | "capability-off";
8
+ /** O help auxiliar: prosa explicativa + sugestão + auto-fix aplicável (por IA/editor).
9
+ * A prosa (`explain`/`suggestion`) é o DEFAULT em inglês (convenção da casa, como as
10
+ * mensagens do checker). `reason` é a CHAVE estável de tradução: um add-on de i18n no
11
+ * frontend mapeia `reason` (+ os campos estruturados) → idioma, sem tocar isto. */
12
+ interface DiagnosticHelp {
13
+ readonly reason: JsIsmReason;
14
+ readonly category: HelpCategory;
15
+ /** "Why this is NOT a language bug" — default prose (English). */
16
+ readonly explain: string;
17
+ /** The correct idiom (e.g. "Use the `length(xs)` operator"). */
18
+ readonly suggestion?: string;
19
+ /** Reescrita mecânica: `from` → `to` (aplicável por code-action ou por uma IA). */
20
+ readonly fix?: {
21
+ readonly from: string;
22
+ readonly to: string;
23
+ };
24
+ /** Âncora de documentação. */
25
+ readonly docs?: string;
26
+ }
27
+ /** Um diagnóstico do checker, possivelmente enriquecido com `help` (aditivo). */
28
+ type ExplainedDiagnostic = Diagnostic & {
29
+ readonly help?: DiagnosticHelp;
30
+ };
31
+ /**
32
+ * Enriquece os diagnósticos de um `CheckResult` com `help` onde o erro é um JS-ism
33
+ * reconhecível. `ast` é a MESMA raiz que foi checada (pra achar pais/nós). Os
34
+ * diagnósticos sem JS-ism reconhecido passam intactos.
35
+ */
36
+ declare function explain(ast: BaseNode, result: CheckResult): ExplainedDiagnostic[];
37
+ /** O `help` de um diagnóstico isolado, dado o mapa de pais (ou `undefined`). */
38
+ declare function helpFor(d: Diagnostic, parents: WeakMap<BaseNode, BaseNode>): DiagnosticHelp | undefined;
39
+
40
+ export { type DiagnosticHelp, type ExplainedDiagnostic, type HelpCategory, type JsIsmReason, explain, helpFor };
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import {walk}from'@tslite/core';import {print}from'@tslite/printer';import {jsMethodReplacements,knownProtoMembersWithoutOperator}from'@tslite/operators';var i="checker D9 / docs/SCOPE-BOUNDARY.md";function h(e,t){let n=T(e);return t.diagnostics.map(s=>{let o=u(s,n);return o?{...s,help:o}:s})}function u(e,t){let n=e.node;switch(n.type){case "NewExpression":return B(n);case "ClassDeclaration":case "ClassExpression":return k();case "FunctionDeclaration":case "FunctionExpression":return O();case "ThisExpression":return E();case "MemberExpression":return e.code==="forbidden-member"?D(n):x(e,n,t)}}function x(e,t,n){if(e.code!=="no-such-member"&&e.code!=="not-object")return;let s=l(t);if(!s)return;let o=jsMethodReplacements[s];if(o)return w(t,s,o,n);if(knownProtoMembersWithoutOperator.has(s))return N(s)}function w(e,t,n,s){let o=print(e.object),a=s.get(e),c=a?.type==="CallExpression"&&a.callee===e,d=c?a.arguments.map(m=>print(m)):[],p=n.call(o,d),g=print(c?a:e);return {reason:"proto-member",category:"portability",explain:`${n.on==="array"?"Arrays":n.on==="string"?"Strings":"Values"} in TSL have no \`.${t}\` method (prototype member). TSL is FP-first and PORTABLE: \`.${t}\` does not translate cleanly to the target (in Python, for instance, it is a function). This is not a language bug \u2014 it is the model.`,suggestion:`Use the \`${n.operator}\` operator (@tslite/operators): \`${p}\`.`,fix:{from:g,to:p},docs:i}}function N(e){return {reason:"proto-member",category:"portability",explain:`\`.${e}\` is a JS prototype method/property \u2014 TSL is FP-first and immutable, so array/string/object methods are not vocabulary. This is not a language bug \u2014 it is the model.`,suggestion:"Rewrite it functionally with @tslite/operators (map/filter/reduce/\u2026), or use the imperative capability if you truly need to mutate.",docs:i}}function D(e){return {reason:"forbidden-substrate",category:"js-ism",explain:`\`.${l(e)??"constructor/prototype/__proto__"}\` is JS runtime substrate (inheritance/prototype) \u2014 it does not exist in TSL, which is FP-first and portable. Forbidden by identity + portability (and it closes the sandbox escape). This is not a language bug \u2014 it is the model.`,docs:i}}function B(e){let t=e.callee,n=t?.type==="Identifier"?t.name:"X";return {reason:"no-new",category:"js-ism",explain:"TSL has no `new` and no classes \u2014 it is FP-first (no OO). `new` was removed on purpose: native capabilities come in as FACTORY functions via DI. Not a language bug.",suggestion:`Inject a factory and call \`${n.charAt(0).toLowerCase()+n.slice(1)}(\u2026)\` instead of \`new ${n}(\u2026)\`.`,docs:i}}function k(){return {reason:"no-class",category:"js-ism",explain:"`class` does not exist in TSL \u2014 it is FP-first, no OO. An instance is just an object with props; behavior comes from functions. This is not a language bug \u2014 it is the model.",suggestion:'Model with objects + functions (a factory function via DI for "methods").',docs:i}}function E(){return {reason:"no-this",category:"js-ism",explain:"`this` does not exist in TSL \u2014 no OO, no implicit receiver. This is not a language bug \u2014 it is the model.",suggestion:"Pass the data as an explicit ARGUMENT instead of `this`.",docs:i}}function O(){return {reason:"no-function-expr",category:"js-ism",explain:"Only ARROW functions are functions in TSL (`(x) => \u2026`). `function(){}` is out (it brings `this`/`arguments`/construction \u2014 OO substrate). This is not a language bug \u2014 it is the model.",suggestion:"Use an arrow: `const f = (x) => \u2026`.",docs:i}}function l(e){if(!e.computed)return e.property.name;let t=e.property;return t.type==="Literal"&&typeof t.value=="string"?t.value:void 0}function T(e){let t=new WeakMap;return walk(e,{"*":(n,s)=>{s&&t.set(n,s);}}),t}export{h as explain,u as helpFor};
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@tslite/explain",
3
+ "version": "0.2.0",
4
+ "description": "TSLite explain — enriches type-check diagnostics with 'why it is NOT a language bug' help for JS/OO habits (proto members, new, class), with operator suggestions and auto-fixes",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/andersondrosa/tslite.git",
26
+ "directory": "packages/explain"
27
+ },
28
+ "keywords": [
29
+ "typescript",
30
+ "diagnostics",
31
+ "developer-experience",
32
+ "error-messages",
33
+ "quickfix",
34
+ "functional-programming"
35
+ ],
36
+ "author": "Anderson D. Rosa <andersondrosa@outlook.com>",
37
+ "license": "MIT",
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "dependencies": {
42
+ "@tslite/core": "0.1.0",
43
+ "@tslite/type-core": "0.2.0",
44
+ "@tslite/checker": "0.2.0",
45
+ "@tslite/operators": "0.2.0",
46
+ "@tslite/printer": "0.1.0"
47
+ },
48
+ "devDependencies": {
49
+ "@tslite/parser": "0.1.0"
50
+ },
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "dev": "tsup --watch",
54
+ "test": "vitest run",
55
+ "test:watch": "vitest",
56
+ "test:coverage": "vitest run --coverage",
57
+ "typecheck": "tsc --noEmit",
58
+ "lint": "eslint src",
59
+ "lint:fix": "eslint src --fix",
60
+ "clean": "rm -rf dist",
61
+ "format": "prettier --write \"{src,tests}/**/*.ts\"",
62
+ "format:check": "prettier --check \"{src,tests}/**/*.ts\""
63
+ }
64
+ }