@produtype/core 1.9.1 → 1.9.3

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.
@@ -26,6 +26,36 @@ const blockComments_1 = require("../analyzer/blockComments");
26
26
  * and is left alone.
27
27
  */
28
28
  const PATTERN_DECLARATION = /^(?:const\s+\w+(?:\s*:[^=]+)?\s*=\s*)?\/(?:[^/\\]|\\.)+\/[gimsuy]*\s*[,;]?$/;
29
+ /**
30
+ * A name given a type, rather than a value.
31
+ *
32
+ * pocketbase's report cited three lines for its cross-origin policy: `AllowedOrigins
33
+ * []string` — a field in a Go struct — `var allowedOrigins []string` in the command
34
+ * that parses the flag, and `allowedOrigins: Array<string>` in a generated `.d.ts`.
35
+ * Not one of them is a decision about origins. The line that is,
36
+ * `config.AllowedOrigins = []string{"*"}` twenty lines further down, was never
37
+ * reached, so a reader was given three declarations to argue with instead of the
38
+ * default that actually applies.
39
+ *
40
+ * It is the same rule as the regex table above, for the same reason: a declaration
41
+ * says what a thing is, and this analyzer claims to say what the code does.
42
+ *
43
+ * The right-hand side has to look like a type, not a value, because `AllowOrigins:
44
+ * config.AllowedOrigins,` is a use and reads almost identically. A type starts with a
45
+ * capital or is one of the primitives, and carries no quotes, no call and no digits —
46
+ * and an object-literal member ends in a comma, which a field signature does not.
47
+ */
48
+ /**
49
+ * `import SwiftUI` has the shape and is not a declaration of anything.
50
+ *
51
+ * A keyword followed by a capitalised word reads exactly like a field given a type,
52
+ * and the first version of this rule hid every Swift and Kotlin import — which is how
53
+ * the native toolkits are detected, so an iOS application lost its interface. The
54
+ * statement keywords are excluded by name; `var`, `let` and `readonly` stay, because
55
+ * those really do introduce a declaration.
56
+ */
57
+ const STATEMENT_KEYWORD = /^(?:import|package|from|export|return|case|new|type|class|struct|interface|enum|func|fun|def|public|private|protected|internal|throw|throws|extends|implements|use|using|namespace|module|require|await|yield|delete|typeof|instanceof|in|is|as|if|else|for|while|switch|do|try|catch|finally|with|assert|raise|lambda|val|const)\b/;
58
+ const TYPE_DECLARATION = /^(?:var\s+|let\s+|readonly\s+)?\w+\??\s*(?::\s*|\s+)(?:\[\]|\*|Array<|Map<|\bstring\b|\bnumber\b|\bboolean\b|\bbool\b|\bany\b|\bunknown\b|\bvoid\b|[A-Z])[\w.<>[\]|&\s]*;?$/;
29
59
  /**
30
60
  * Prose about the code, rather than the code.
31
61
  *
@@ -56,9 +86,13 @@ const COMMENT_LINE = /^(?:\/\/|\/\*|\*\/?|#(?![![])(?!!)|<!--|--\s)/;
56
86
  *
57
87
  * Nothing in the shape of the line tells the two apart, so the rule is not made.
58
88
  */
89
+ function declaresAType(trimmed) {
90
+ const withoutDeclarator = trimmed.replace(/^(?:var|let|readonly)\s+/, '');
91
+ return !STATEMENT_KEYWORD.test(withoutDeclarator) && TYPE_DECLARATION.test(trimmed);
92
+ }
59
93
  function declaresRatherThanDoes(line) {
60
94
  const trimmed = line.trim();
61
- return COMMENT_LINE.test(trimmed) || PATTERN_DECLARATION.test(trimmed);
95
+ return COMMENT_LINE.test(trimmed) || PATTERN_DECLARATION.test(trimmed) || declaresAType(trimmed);
62
96
  }
63
97
  /**
64
98
  * Whether this line may be quoted back to the reader as something the code does.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@produtype/core",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
4
4
  "description": "Deterministic CLI and library that analyzes a web application repository and reports how far it is from production-ready for the kind of product it is meant to be.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -37,7 +37,7 @@
37
37
  "docs:stacks": "npm run build && node scripts/sync-readme-stacks.mjs",
38
38
  "prepare": "npm run build",
39
39
  "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
40
- "prepublishOnly": "npm run build && node scripts/assert-no-ai.mjs && npm test"
40
+ "prepublishOnly": "npm run build && npm run lint && node scripts/assert-no-ai.mjs && npm test"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18"