@ecoma-io/archkeep 0.16.0 → 0.16.1
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/package.json +1 -1
- package/src/analysis/csharp.mjs +38 -9
- package/src/analysis/go.mjs +15 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecoma-io/archkeep",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Architecture enforcement for polyglot repositories — dependency graphs and module boundaries for Go, Rust, Python, TypeScript, JavaScript, Vue, Java and Kotlin",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"architecture",
|
package/src/analysis/csharp.mjs
CHANGED
|
@@ -70,6 +70,11 @@
|
|
|
70
70
|
* same class of limit Kotlin's backtick segments pin.
|
|
71
71
|
* - An **unterminated directive** (no `;` before end of line) is not a
|
|
72
72
|
* complete directive and is not read.
|
|
73
|
+
* - A **statement whose initializer opens but never closes** (`using var x =
|
|
74
|
+
* new F {`, the `;` never arriving) is neither read nor flagged — the `{`
|
|
75
|
+
* behind the resource's `=` is the statement's own (#469), the same
|
|
76
|
+
* silence a `using (r) {` block has always held. The malformation scan
|
|
77
|
+
* judges directives only.
|
|
73
78
|
*/
|
|
74
79
|
import { csharpNamespaceIndex } from "./dotnet/namespaces.mjs";
|
|
75
80
|
import { maskCSharpComments } from "./dotnet/mask.mjs";
|
|
@@ -130,6 +135,13 @@ const CS_EXTERN_ALIAS = new RegExp(
|
|
|
130
135
|
/** Exactly one identifier followed by `=`: the alias form. */
|
|
131
136
|
const ALIAS_FORM = new RegExp(String.raw`^(${SEG})[ \t]*=[ \t]*(.+)$`, "su");
|
|
132
137
|
|
|
138
|
+
/**
|
|
139
|
+
* One bare identifier, optionally verbatim (`@class`): an alias's own name.
|
|
140
|
+
* The malformation scan reads it backwards — the text before an initializer
|
|
141
|
+
* `=` is an alias's name only when it is NOT this shape.
|
|
142
|
+
*/
|
|
143
|
+
const ALIAS_NAME = new RegExp(String.raw`^@?${SEG}$`, "u");
|
|
144
|
+
|
|
133
145
|
/** A dotted name, optionally behind the `global::` qualifier: the plain form. */
|
|
134
146
|
const PLAIN_FORM = new RegExp(String.raw`^(?:global::)?(${DOTTED_NAME})$`, "u");
|
|
135
147
|
|
|
@@ -262,10 +274,17 @@ export function parseCSharpDirectiveSites(csharpText) {
|
|
|
262
274
|
* from one the file truncates — a failed write, a merge marker left
|
|
263
275
|
* mid-directive — which used to parse as zero directive sites with no
|
|
264
276
|
* failure, byte-for-byte identical to a file that imports nothing (#419).
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
277
|
+
* Statement shapes hold no opinion at all, by two markers the text shows
|
|
278
|
+
* before any terminator arrives: a `(` right after the keyword is the
|
|
279
|
+
* parenthesized family — `using (var s = f()) { … }`, `using (x);` — and an
|
|
280
|
+
* `=` between the keyword and the walk's first `{` is the declaration family
|
|
281
|
+
* (#469) whenever MORE than one bare identifier precedes it — `var writer`,
|
|
282
|
+
* `Dictionary<string, int> map`, every declaration spelling — because a
|
|
283
|
+
* brace behind a resource's own `=` is that statement's initializer, while
|
|
284
|
+
* the first `{` behind a directive can only be the file's truncation. One
|
|
285
|
+
* bare identifier before the `=` is an ALIAS's own name (`using Pair = …`),
|
|
286
|
+
* the brace then belongs to whatever follows, and the truncated alias stays
|
|
287
|
+
* loud. A statement's `;` may arrive inside its own
|
|
269
288
|
* block, so the scan has no opinion there. One silence the rule keeps: a
|
|
270
289
|
* missing `;` that a LATER declaration supplies its own (`extern alias X`
|
|
271
290
|
* then `namespace Shop.App;`) is not seen — the walk reads the next
|
|
@@ -324,11 +343,21 @@ export function csharpDirectiveMalformations(csharpText) {
|
|
|
324
343
|
if (source[at] === "(") continue;
|
|
325
344
|
const next = usingTerminatorAfter(at);
|
|
326
345
|
if (next === undefined || next[0] === "{") {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
346
|
+
// The declaration family's initializer `=` (#469) — argued beside the
|
|
347
|
+
// openers above: an `=` whose prefix is more than one bare identifier
|
|
348
|
+
// is a resource's own, and the brace with it. One bare identifier is
|
|
349
|
+
// an alias's own name, the brace belongs to whatever follows, and the
|
|
350
|
+
// truncated alias stays loud.
|
|
351
|
+
const eq = next !== undefined ? source.indexOf("=", at) : -1;
|
|
352
|
+
const initializer =
|
|
353
|
+
eq !== -1 && eq < next.index && !ALIAS_NAME.test(source.slice(at, eq).trim());
|
|
354
|
+
if (next === undefined || !initializer) {
|
|
355
|
+
flag(
|
|
356
|
+
m.index + m[0].indexOf("using"),
|
|
357
|
+
"using",
|
|
358
|
+
"a `using` directive never reaches its `;` — the file is truncated or malformed, so its imports cannot be read",
|
|
359
|
+
);
|
|
360
|
+
}
|
|
332
361
|
}
|
|
333
362
|
}
|
|
334
363
|
const externTerminatorAfter = terminatorAfter();
|
package/src/analysis/go.mjs
CHANGED
|
@@ -44,6 +44,13 @@
|
|
|
44
44
|
* quote closed on a later line, a `)` supplied from a function body below —
|
|
45
45
|
* produce a record today and stay the documented parse limits above.
|
|
46
46
|
*
|
|
47
|
+
* One misread answers neither record nor failure, named as a limit rather
|
|
48
|
+
* than fixed (#468's neighbourhood): a bare `import` whose line ends with
|
|
49
|
+
* no path and whose `(` arrives from the statement BELOW it — `import`
|
|
50
|
+
* alone, then `const (` opening the next — is read as that block, and the
|
|
51
|
+
* doubly-broken file stays silent. Rejecting it needs a same-line rule
|
|
52
|
+
* that would flag the legal `import` newline `"path"` continuation.
|
|
53
|
+
*
|
|
47
54
|
* ## An unreadable go.mod refuses, it does not skip (#405)
|
|
48
55
|
*
|
|
49
56
|
* `parseGoModulePath` parses content; it never sees a failed read. Reading a
|
|
@@ -310,7 +317,14 @@ export function goImportMalformations(goText) {
|
|
|
310
317
|
// close just found rather than rescanning the text before it.
|
|
311
318
|
let lastClose = 0;
|
|
312
319
|
let unclosedSince = -1;
|
|
313
|
-
|
|
320
|
+
// `import` must be the keyword, never a prefix of an identifier (#468): a
|
|
321
|
+
// const member named `importPath` sits at line head exactly where the
|
|
322
|
+
// keyword would, and reading it as the keyword flagged a compiling file
|
|
323
|
+
// "an import states no path". Go lexes by maximal munch — letters, digits,
|
|
324
|
+
// and `_` continuing the word make it one identifier — so the lookahead
|
|
325
|
+
// excludes exactly those, and every legal follower (`(`, a quote, an
|
|
326
|
+
// alias, whitespace) still opens.
|
|
327
|
+
for (const m of source.matchAll(/(?:^|;)[ \t]*import(?![\p{L}\p{Nd}_])/gmu)) {
|
|
314
328
|
let at = m.index + m[0].length;
|
|
315
329
|
while (at < source.length && /\s/u.test(source[at])) at += 1;
|
|
316
330
|
if (at >= source.length) {
|