@produtype/core 1.9.3 → 1.10.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/utils/textSearch.js +54 -14
- package/package.json +1 -1
package/dist/utils/textSearch.js
CHANGED
|
@@ -127,6 +127,54 @@ function isCitableLine(line) {
|
|
|
127
127
|
* on is not worth the one it displaces.
|
|
128
128
|
*/
|
|
129
129
|
const MAX_CITABLE_LINE = 500;
|
|
130
|
+
/**
|
|
131
|
+
* A placeholder is not a value.
|
|
132
|
+
*
|
|
133
|
+
* pocketbase was reported as having tenant boundaries — `passed`, which raises a
|
|
134
|
+
* score — and the only two strong matches in its readable source were
|
|
135
|
+
* `"Ex. https://login.microsoftonline.com/YOUR_DIRECTORY_TENANT_ID/oauth2/v2.0/authorize"`,
|
|
136
|
+
* twice, in the help text of the form where somebody configures Microsoft sign-in.
|
|
137
|
+
* Microsoft Entra calls its directory a tenant; the string is telling a reader where
|
|
138
|
+
* to paste theirs. pocketbase has no organizations at all, and the rest of that
|
|
139
|
+
* finding was Apple's developer `teamId`, a weak word that cannot stand alone.
|
|
140
|
+
*
|
|
141
|
+
* `YOUR_SOMETHING` is the convention for "replace this", in documentation, in example
|
|
142
|
+
* configuration and in the help text beside a field. This analyzer already knows the
|
|
143
|
+
* shape: `your[_-]?secret` has been in the weak-secret list since the beginning.
|
|
144
|
+
*
|
|
145
|
+
* The token around the match is what decides, not the line. A line may hold a
|
|
146
|
+
* placeholder and a real value both, and only the matched one is being judged.
|
|
147
|
+
*/
|
|
148
|
+
const PLACEHOLDER_TOKEN = /^(?:your|my|sample|example|placeholder|changeme|todo|xxx+)[_-]/i;
|
|
149
|
+
function insideAPlaceholder(line, index, length) {
|
|
150
|
+
let start = index;
|
|
151
|
+
while (start > 0 && /[A-Za-z0-9_-]/.test(line[start - 1]))
|
|
152
|
+
start--;
|
|
153
|
+
let end = index + length;
|
|
154
|
+
while (end < line.length && /[A-Za-z0-9_-]/.test(line[end]))
|
|
155
|
+
end++;
|
|
156
|
+
return PLACEHOLDER_TOKEN.test(line.slice(start, end));
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Where a needle first matches, or -1. Shared so that both searches below judge a
|
|
160
|
+
* match the same way.
|
|
161
|
+
*/
|
|
162
|
+
function findNeedle(line, needle) {
|
|
163
|
+
if (typeof needle === 'string') {
|
|
164
|
+
const index = line.indexOf(needle);
|
|
165
|
+
return index === -1 ? null : { index, length: needle.length };
|
|
166
|
+
}
|
|
167
|
+
const found = new RegExp(needle.source, needle.flags.replace('g', '')).exec(line);
|
|
168
|
+
return found ? { index: found.index, length: found[0].length } : null;
|
|
169
|
+
}
|
|
170
|
+
function matchesHere(line, needles) {
|
|
171
|
+
for (const needle of needles) {
|
|
172
|
+
const found = findNeedle(line, needle);
|
|
173
|
+
if (found && !insideAPlaceholder(line, found.index, found.length))
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
130
178
|
/**
|
|
131
179
|
* The lines of one already-read file that match, with the same hygiene the file
|
|
132
180
|
* search applies: no comments, no pattern tables, no minified lines.
|
|
@@ -157,12 +205,8 @@ function matchLines(text, needles, file = '') {
|
|
|
157
205
|
continue;
|
|
158
206
|
if (declaresRatherThanDoes(line))
|
|
159
207
|
continue;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (hit) {
|
|
163
|
-
matches.push({ file, line: i + 1, snippet: line.trim().slice(0, 200) });
|
|
164
|
-
break;
|
|
165
|
-
}
|
|
208
|
+
if (matchesHere(line, needles)) {
|
|
209
|
+
matches.push({ file, line: i + 1, snippet: line.trim().slice(0, 200) });
|
|
166
210
|
}
|
|
167
211
|
}
|
|
168
212
|
return matches;
|
|
@@ -205,14 +249,10 @@ async function searchInFiles(root, files, needles, limit = 25, keep) {
|
|
|
205
249
|
continue;
|
|
206
250
|
if (declaresRatherThanDoes(line))
|
|
207
251
|
continue;
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
if (
|
|
211
|
-
|
|
212
|
-
if (!keep || keep(match))
|
|
213
|
-
matches.push(match);
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
252
|
+
if (matchesHere(line, needles)) {
|
|
253
|
+
const match = { file, line: i + 1, snippet: line.trim().slice(0, 200) };
|
|
254
|
+
if (!keep || keep(match))
|
|
255
|
+
matches.push(match);
|
|
216
256
|
}
|
|
217
257
|
if (matches.length >= limit)
|
|
218
258
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@produtype/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
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": {
|