@velarscript/cli 0.12.1 → 0.13.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/README.md +4 -12
- package/dist/browser-process-owner.d.ts +23 -0
- package/dist/browser-process-owner.d.ts.map +1 -1
- package/dist/browser-process-owner.js +46 -2
- package/dist/browser-process-owner.js.map +1 -1
- package/dist/browser-test-runner.d.ts.map +1 -1
- package/dist/browser-test-runner.js +110 -14
- package/dist/browser-test-runner.js.map +1 -1
- package/dist/cli.js +131 -68
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -4
- package/dist/config.js.map +1 -1
- package/dist/dev-server.d.ts +18 -0
- package/dist/dev-server.d.ts.map +1 -1
- package/dist/dev-server.js +168 -8
- package/dist/dev-server.js.map +1 -1
- package/dist/extension-metadata.d.ts +6 -0
- package/dist/extension-metadata.d.ts.map +1 -1
- package/dist/extension-metadata.js +70 -4
- package/dist/extension-metadata.js.map +1 -1
- package/dist/format-guard.d.ts +20 -0
- package/dist/format-guard.d.ts.map +1 -0
- package/dist/format-guard.js +13 -0
- package/dist/format-guard.js.map +1 -0
- package/dist/framework-host.d.ts.map +1 -1
- package/dist/framework-host.js +15 -2
- package/dist/framework-host.js.map +1 -1
- package/dist/language-server-bundle-entry.js +0 -2
- package/dist/language-server-bundle-entry.js.map +1 -1
- package/dist/language-server-tool.d.ts.map +1 -1
- package/dist/language-server-tool.js +0 -2
- package/dist/language-server-tool.js.map +1 -1
- package/dist/language-server.d.ts +1 -1
- package/dist/language-server.d.ts.map +1 -1
- package/dist/language-server.js +87 -293
- package/dist/language-server.js.map +1 -1
- package/dist/local-request-guard.d.ts +18 -0
- package/dist/local-request-guard.d.ts.map +1 -0
- package/dist/local-request-guard.js +75 -0
- package/dist/local-request-guard.js.map +1 -0
- package/dist/mechanical-fixer.d.ts.map +1 -1
- package/dist/mechanical-fixer.js +116 -2
- package/dist/mechanical-fixer.js.map +1 -1
- package/dist/module-assets.d.ts +23 -0
- package/dist/module-assets.d.ts.map +1 -1
- package/dist/module-assets.js +216 -14
- package/dist/module-assets.js.map +1 -1
- package/dist/node-application.d.ts +7 -2
- package/dist/node-application.d.ts.map +1 -1
- package/dist/node-application.js +44 -14
- package/dist/node-application.js.map +1 -1
- package/dist/node-runtime-dependencies.d.ts +2 -0
- package/dist/node-runtime-dependencies.d.ts.map +1 -0
- package/dist/node-runtime-dependencies.js +24 -0
- package/dist/node-runtime-dependencies.js.map +1 -0
- package/dist/npm.d.ts +29 -0
- package/dist/npm.d.ts.map +1 -1
- package/dist/npm.js +39 -2
- package/dist/npm.js.map +1 -1
- package/dist/ownership-graph.d.ts.map +1 -1
- package/dist/ownership-graph.js +155 -38
- package/dist/ownership-graph.js.map +1 -1
- package/dist/package-manager.d.ts.map +1 -1
- package/dist/package-manager.js +4 -1
- package/dist/package-manager.js.map +1 -1
- package/dist/preview-server.d.ts.map +1 -1
- package/dist/preview-server.js +12 -4
- package/dist/preview-server.js.map +1 -1
- package/dist/production-build.d.ts.map +1 -1
- package/dist/production-build.js +24 -6
- package/dist/production-build.js.map +1 -1
- package/dist/production-verifier.js +3 -0
- package/dist/production-verifier.js.map +1 -1
- package/dist/project-check.d.ts +14 -1
- package/dist/project-check.d.ts.map +1 -1
- package/dist/project-check.js +17 -4
- package/dist/project-check.js.map +1 -1
- package/dist/project-format.d.ts +9 -0
- package/dist/project-format.d.ts.map +1 -1
- package/dist/project-format.js +13 -0
- package/dist/project-format.js.map +1 -1
- package/dist/project-semantic.d.ts.map +1 -1
- package/dist/project-semantic.js +15 -4
- package/dist/project-semantic.js.map +1 -1
- package/dist/project.d.ts +25 -0
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js +341 -42
- package/dist/project.js.map +1 -1
- package/dist/reproduction.d.ts +18 -0
- package/dist/reproduction.d.ts.map +1 -1
- package/dist/reproduction.js +47 -6
- package/dist/reproduction.js.map +1 -1
- package/dist/stable-order.d.ts +17 -0
- package/dist/stable-order.d.ts.map +1 -0
- package/dist/stable-order.js +19 -0
- package/dist/stable-order.js.map +1 -0
- package/dist/standard-modules.d.ts +2 -2
- package/dist/standard-modules.d.ts.map +1 -1
- package/dist/standard-modules.js +2 -2
- package/dist/standard-modules.js.map +1 -1
- package/dist/static-deployment.d.ts.map +1 -1
- package/dist/static-deployment.js +27 -0
- package/dist/static-deployment.js.map +1 -1
- package/dist/test-runner.d.ts.map +1 -1
- package/dist/test-runner.js +196 -100
- package/dist/test-runner.js.map +1 -1
- package/dist/test-worker.d.ts +64 -0
- package/dist/test-worker.d.ts.map +1 -0
- package/dist/test-worker.js +161 -0
- package/dist/test-worker.js.map +1 -0
- package/dist/typescript-declarations.d.ts +1 -1
- package/dist/typescript-declarations.d.ts.map +1 -1
- package/dist/typescript-declarations.js +233 -21
- package/dist/typescript-declarations.js.map +1 -1
- package/dist/unowned-errors.d.ts +15 -2
- package/dist/unowned-errors.d.ts.map +1 -1
- package/dist/unowned-errors.js +13 -2
- package/dist/unowned-errors.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/workspace-index.d.ts.map +1 -1
- package/dist/workspace-index.js +42 -17
- package/dist/workspace-index.js.map +1 -1
- package/package.json +7 -8
- package/skill/ai-skill-node.md +74 -9
- package/skill/ai-skill-web.md +51 -1
- package/skill/ai-skill.md +36 -13
- package/dist/official-script-language-service.d.ts +0 -2
- package/dist/official-script-language-service.d.ts.map +0 -1
- package/dist/official-script-language-service.js +0 -10
- package/dist/official-script-language-service.js.map +0 -1
- package/dist/official-tool-assets.d.ts +0 -3
- package/dist/official-tool-assets.d.ts.map +0 -1
- package/dist/official-tool-assets.js +0 -60
- package/dist/official-tool-assets.js.map +0 -1
- package/dist/script-language-service.d.ts +0 -82
- package/dist/script-language-service.d.ts.map +0 -1
- package/dist/script-language-service.js +0 -18
- package/dist/script-language-service.js.map +0 -1
|
@@ -67,7 +67,7 @@ export async function loadTypeScriptDeclarations(source, importerPath) {
|
|
|
67
67
|
return null;
|
|
68
68
|
}
|
|
69
69
|
try {
|
|
70
|
-
const bridge = await loadTypeScriptDeclarationGraph(root, path, packageName);
|
|
70
|
+
const bridge = await loadTypeScriptDeclarationGraph(root, path, packageName, source);
|
|
71
71
|
return { ...bridge, dependencies: [...unique([manifestPath, ...bridge.dependencies])].sort() };
|
|
72
72
|
}
|
|
73
73
|
catch {
|
|
@@ -113,10 +113,16 @@ function declarationFileCandidates(path) {
|
|
|
113
113
|
function isDeclarationFile(path) {
|
|
114
114
|
return path.endsWith(".d.ts") || path.endsWith(".d.mts") || path.endsWith(".d.cts");
|
|
115
115
|
}
|
|
116
|
-
async function loadTypeScriptDeclarationGraph(root, entry, packageSource) {
|
|
116
|
+
async function loadTypeScriptDeclarationGraph(root, entry, packageSource, importedSpecifier = packageSource) {
|
|
117
117
|
const [rootPath, entryPath] = await Promise.all([realpath(root), realpath(entry)]);
|
|
118
118
|
if (!insideRoot(rootPath, entryPath))
|
|
119
119
|
throw new Error("TypeScript declaration entry escapes its package root");
|
|
120
|
+
// The specifiers a `declare module "…"` block may legitimately declare: the
|
|
121
|
+
// package this graph belongs to, in the legacy ambient spelling. A subpath
|
|
122
|
+
// import declares its own specifier, so `pkg/sub.d.ts` writing
|
|
123
|
+
// `declare module "pkg/sub" { … }` is that subpath's own contract and must
|
|
124
|
+
// not be excised as somebody else's ambient block.
|
|
125
|
+
const ownModules = new Set([importedSpecifier, packageSource, packageNameOf(packageSource)]);
|
|
120
126
|
const cache = new Map();
|
|
121
127
|
const visiting = new Set();
|
|
122
128
|
const counted = new Set();
|
|
@@ -150,7 +156,7 @@ async function loadTypeScriptDeclarationGraph(root, entry, packageSource) {
|
|
|
150
156
|
const importedTypes = new Map();
|
|
151
157
|
const importedRegistry = new Map();
|
|
152
158
|
const importWarnings = [];
|
|
153
|
-
for (const declarationImport of declarationImports(source)) {
|
|
159
|
+
for (const declarationImport of declarationImports(source, ownModules)) {
|
|
154
160
|
if (declarationImport.unsupported) {
|
|
155
161
|
importWarnings.push(`Namespace declaration import from '${declarationImport.source}' is outside the VelarScript declaration bridge and was kept as unknown`);
|
|
156
162
|
continue;
|
|
@@ -176,7 +182,7 @@ async function loadTypeScriptDeclarationGraph(root, entry, packageSource) {
|
|
|
176
182
|
}
|
|
177
183
|
}
|
|
178
184
|
}
|
|
179
|
-
const local = parseTypeScriptDeclarations(source, path, origin, true, importedTypes, importedRegistry);
|
|
185
|
+
const local = parseTypeScriptDeclarations(source, path, origin, true, importedTypes, importedRegistry, ownModules);
|
|
180
186
|
const exports = new Map(local.exports);
|
|
181
187
|
const typeExports = new Map(local.typeExports);
|
|
182
188
|
const classes = new Map(local.classes);
|
|
@@ -184,7 +190,7 @@ async function loadTypeScriptDeclarationGraph(root, entry, packageSource) {
|
|
|
184
190
|
const warnings = [...importWarnings, ...local.warnings];
|
|
185
191
|
const explicit = new Set(exports.keys());
|
|
186
192
|
const explicitTypes = new Set(typeExports.keys());
|
|
187
|
-
const reexports = declarationReexports(source);
|
|
193
|
+
const reexports = declarationReexports(source, ownModules);
|
|
188
194
|
for (const reexport of reexports.filter((item) => item.names !== null)) {
|
|
189
195
|
const childPath = await resolveDeclarationReexport(rootPath, path, reexport.source);
|
|
190
196
|
if (!childPath) {
|
|
@@ -298,8 +304,8 @@ async function loadTypeScriptDeclarationGraph(root, entry, packageSource) {
|
|
|
298
304
|
function emptyDeclarationBridge(path, warning) {
|
|
299
305
|
return { path, dependencies: [path], exports: new Map(), typeExports: new Map(), classes: new Map(), classRegistry: new Map(), warnings: [warning] };
|
|
300
306
|
}
|
|
301
|
-
function declarationReexports(source) {
|
|
302
|
-
const text = source
|
|
307
|
+
function declarationReexports(source, ownModules) {
|
|
308
|
+
const text = excludeAmbientBlocks(stripDeclarationComments(source), [], ownModules);
|
|
303
309
|
const output = [];
|
|
304
310
|
const named = /export\s+(type\s+)?\{([\s\S]*?)\}\s*from\s*["']([^"']+)["']\s*;?/gu;
|
|
305
311
|
for (const match of text.matchAll(named)) {
|
|
@@ -317,8 +323,8 @@ function declarationReexports(source) {
|
|
|
317
323
|
output.push({ source: match[1], names: null });
|
|
318
324
|
return output;
|
|
319
325
|
}
|
|
320
|
-
function declarationImports(source) {
|
|
321
|
-
const text = source
|
|
326
|
+
function declarationImports(source, ownModules) {
|
|
327
|
+
const text = excludeAmbientBlocks(stripDeclarationComments(source), [], ownModules);
|
|
322
328
|
const output = [];
|
|
323
329
|
const pattern = /^[ \t]*import\s+(?:type\s+)?([\s\S]*?)\s+from\s*["']([^"']+)["']\s*;?/gmu;
|
|
324
330
|
for (const match of text.matchAll(pattern)) {
|
|
@@ -394,12 +400,12 @@ function renameDeclarationExport(type, name) {
|
|
|
394
400
|
function renameDeclarationType(type, name) {
|
|
395
401
|
return type.kind === "class" ? { ...type, name } : type;
|
|
396
402
|
}
|
|
397
|
-
export function parseTypeScriptDeclarations(source, path = "<types>", moduleSource = path, reexportsHandled = false, importedTypes = new Map(), importedClassRegistry = new Map()) {
|
|
403
|
+
export function parseTypeScriptDeclarations(source, path = "<types>", moduleSource = path, reexportsHandled = false, importedTypes = new Map(), importedClassRegistry = new Map(), ownModules = new Set()) {
|
|
398
404
|
if (Buffer.byteLength(source, "utf8") > MAX_TYPESCRIPT_DECLARATION_BYTES) {
|
|
399
405
|
throw new RangeError(`${path} exceeds the 2 MiB TypeScript declaration bridge limit`);
|
|
400
406
|
}
|
|
401
|
-
const text = source.replace(/\/\*[\s\S]*?\*\//gu, "").replace(/\/\/[^\n]*/gu, "");
|
|
402
407
|
const warnings = [];
|
|
408
|
+
const text = excludeAmbientBlocks(stripDeclarationComments(source), warnings, ownModules);
|
|
403
409
|
const aliases = new Map();
|
|
404
410
|
const interfaces = new Map();
|
|
405
411
|
const invalidInterfaces = new Set();
|
|
@@ -890,7 +896,7 @@ function parseClassDeclaration(declaration, parse, warnings, moduleSource, class
|
|
|
890
896
|
target.set(accessor.name, contract);
|
|
891
897
|
continue;
|
|
892
898
|
}
|
|
893
|
-
const property = /^((?:(?:public|static|readonly|declare)\s+)*)?([A-Za-z_$][\w$]*)(\?)?\s*:\s*(.+)$/
|
|
899
|
+
const property = /^((?:(?:public|static|readonly|declare)\s+)*)?([A-Za-z_$][\w$]*)(\?)?\s*:\s*(.+)$/su.exec(member);
|
|
894
900
|
if (property) {
|
|
895
901
|
const modifiers = new Set((property[1] ?? "").trim().split(/\s+/u).filter(Boolean));
|
|
896
902
|
const target = modifiers.has("static") ? staticFields : fields;
|
|
@@ -1004,6 +1010,15 @@ function parseRestElementType(source, parse) {
|
|
|
1004
1010
|
const generic = /^(?:Array|ReadonlyArray)\s*<([\s\S]+)>$/u.exec(value);
|
|
1005
1011
|
return generic && splitTopLevel(generic[1] ?? "", ",").length === 1 ? parse(generic[1] ?? "unknown") : null;
|
|
1006
1012
|
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Drops TypeScript's `this` pseudo-parameter. It only types the receiver, it
|
|
1015
|
+
* carries no runtime argument, and it is legal only in first position — so
|
|
1016
|
+
* counting it as positional gives every correct call site an arity error with
|
|
1017
|
+
* no value the author could supply.
|
|
1018
|
+
*/
|
|
1019
|
+
function withoutThisParameter(parts) {
|
|
1020
|
+
return parts.length > 0 && /^this\s*:/u.test(parts[0]) ? parts.slice(1) : parts;
|
|
1021
|
+
}
|
|
1007
1022
|
function parseParameters(source, parse, warnings) {
|
|
1008
1023
|
if (!source.trim())
|
|
1009
1024
|
return { types: [], required: 0 };
|
|
@@ -1012,9 +1027,9 @@ function parseParameters(source, parse, warnings) {
|
|
|
1012
1027
|
let optionalSeen = false;
|
|
1013
1028
|
let invalid = false;
|
|
1014
1029
|
let rest;
|
|
1015
|
-
const parts = splitTopLevel(source, ",");
|
|
1030
|
+
const parts = withoutThisParameter(splitTopLevel(source, ","));
|
|
1016
1031
|
for (const [index, part] of parts.entries()) {
|
|
1017
|
-
const match = /^(\.\.\.)?[A-Za-z_$][\w$]*(\?)?\s*:\s*(.+)$/
|
|
1032
|
+
const match = /^(\.\.\.)?[A-Za-z_$][\w$]*(\?)?\s*:\s*(.+)$/su.exec(part.trim());
|
|
1018
1033
|
if (!match) {
|
|
1019
1034
|
warnings.push(`Unsupported parameter declaration '${part.trim()}' was kept as unknown`);
|
|
1020
1035
|
types.push(unsupportedType);
|
|
@@ -1058,9 +1073,9 @@ function parseClassConstructorParameters(source, parse, warnings) {
|
|
|
1058
1073
|
let required = 0;
|
|
1059
1074
|
let optionalSeen = false;
|
|
1060
1075
|
let rest;
|
|
1061
|
-
const parts = splitTopLevel(source, ",");
|
|
1076
|
+
const parts = withoutThisParameter(splitTopLevel(source, ","));
|
|
1062
1077
|
for (const [index, part] of parts.entries()) {
|
|
1063
|
-
const match = /^((?:(?:public|private|protected|readonly)\s+)*)(\.\.\.)?([A-Za-z_$][\w$]*)(\?)?\s*:\s*(.+)$/
|
|
1078
|
+
const match = /^((?:(?:public|private|protected|readonly)\s+)*)(\.\.\.)?([A-Za-z_$][\w$]*)(\?)?\s*:\s*(.+)$/su.exec(part.trim());
|
|
1064
1079
|
if (!match) {
|
|
1065
1080
|
warnings.push(`Unsupported constructor parameter declaration '${part.trim()}' was kept as unknown`);
|
|
1066
1081
|
types.push(unsupportedType);
|
|
@@ -1277,7 +1292,7 @@ function objectType(source, aliases, warnings, stack, classTypes, direction) {
|
|
|
1277
1292
|
const optionalFields = new Set();
|
|
1278
1293
|
let invalidInputShape = false;
|
|
1279
1294
|
for (const part of splitFields(source)) {
|
|
1280
|
-
const match = /^(readonly\s+)?([A-Za-z_$][\w$]*)(\?)?\s*:\s*(.+)$/
|
|
1295
|
+
const match = /^(readonly\s+)?([A-Za-z_$][\w$]*)(\?)?\s*:\s*(.+)$/su.exec(part.trim());
|
|
1281
1296
|
if (match) {
|
|
1282
1297
|
const name = match[2];
|
|
1283
1298
|
const type = parseTsType(match[4] ?? "unknown", aliases, warnings, stack, classTypes, match[1] ? direction : "invariant");
|
|
@@ -1405,6 +1420,108 @@ function skipWhitespace(source, start) {
|
|
|
1405
1420
|
cursor += 1;
|
|
1406
1421
|
return cursor;
|
|
1407
1422
|
}
|
|
1423
|
+
/**
|
|
1424
|
+
* Finds the closing quote of the string literal that opens at `start`, or the
|
|
1425
|
+
* last character it can belong to when the literal is never closed.
|
|
1426
|
+
*/
|
|
1427
|
+
function closingQuote(source, start) {
|
|
1428
|
+
const quote = source[start];
|
|
1429
|
+
for (let index = start + 1; index < source.length; index += 1) {
|
|
1430
|
+
const character = source[index];
|
|
1431
|
+
if (character === "\\") {
|
|
1432
|
+
index += 1;
|
|
1433
|
+
continue;
|
|
1434
|
+
}
|
|
1435
|
+
if (character === quote)
|
|
1436
|
+
return index;
|
|
1437
|
+
if (quote !== "`" && character === "\n")
|
|
1438
|
+
return index - 1;
|
|
1439
|
+
}
|
|
1440
|
+
return source.length - 1;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Removes comments from a declaration file without disturbing string literal
|
|
1444
|
+
* types. A `.d.ts` routinely writes `/*`, `*` + `/` or `//` inside a string
|
|
1445
|
+
* literal type — URL literals, glob literals, template literal types — and a
|
|
1446
|
+
* regex stripper eats every real declaration between two of them with no word
|
|
1447
|
+
* to the author. Comment bytes become spaces so that every offset recorded
|
|
1448
|
+
* against the result still addresses the same character of `source`.
|
|
1449
|
+
*/
|
|
1450
|
+
function stripDeclarationComments(source) {
|
|
1451
|
+
let output = "";
|
|
1452
|
+
let index = 0;
|
|
1453
|
+
while (index < source.length) {
|
|
1454
|
+
const character = source[index];
|
|
1455
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
1456
|
+
const end = closingQuote(source, index);
|
|
1457
|
+
output += source.slice(index, end + 1);
|
|
1458
|
+
index = end + 1;
|
|
1459
|
+
continue;
|
|
1460
|
+
}
|
|
1461
|
+
if (character === "/" && source[index + 1] === "*") {
|
|
1462
|
+
const close = source.indexOf("*/", index + 2);
|
|
1463
|
+
const end = close < 0 ? source.length : close + 2;
|
|
1464
|
+
output += " ".repeat(end - index);
|
|
1465
|
+
index = end;
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
if (character === "/" && source[index + 1] === "/") {
|
|
1469
|
+
let end = index;
|
|
1470
|
+
while (end < source.length && source[end] !== "\n")
|
|
1471
|
+
end += 1;
|
|
1472
|
+
output += " ".repeat(end - index);
|
|
1473
|
+
index = end;
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
output += character;
|
|
1477
|
+
index += 1;
|
|
1478
|
+
}
|
|
1479
|
+
return output;
|
|
1480
|
+
}
|
|
1481
|
+
const ambientBlockPattern = /(?:^|[;{}\r\n])[\t ]*((?:export\s+)?declare\s+(?:global|namespace\s+[A-Za-z_$][\w$.]*|module\s+(?:"[^"\r\n]*"|'[^'\r\n]*'|[A-Za-z_$][\w$.]*))|(?:export\s+)?(?:namespace|module)\s+[A-Za-z_$][\w$.]*)\s*\{/gu;
|
|
1482
|
+
/**
|
|
1483
|
+
* Blanks `declare global`, `declare namespace X` and `declare module "x"`
|
|
1484
|
+
* bodies. The declaration sweeps have no concept of a nested declaration
|
|
1485
|
+
* scope, so without this an `export` inside one of these blocks is read as a
|
|
1486
|
+
* module export the package does not have — a clean `velar check` that links
|
|
1487
|
+
* to a host `SyntaxError` at run time. The span becomes spaces rather than
|
|
1488
|
+
* disappearing so recorded offsets stay valid, and each excised block is
|
|
1489
|
+
* reported.
|
|
1490
|
+
*
|
|
1491
|
+
* `ownModules` names the specifiers this file is the declaration for. A
|
|
1492
|
+
* `declare module "self"` block is that package's own contract in the legacy
|
|
1493
|
+
* ambient spelling, so only its head and braces are blanked and its members
|
|
1494
|
+
* stay module members.
|
|
1495
|
+
*/
|
|
1496
|
+
function excludeAmbientBlocks(source, warnings, ownModules = new Set()) {
|
|
1497
|
+
let text = source;
|
|
1498
|
+
let blankedUntil = 0;
|
|
1499
|
+
for (const match of source.matchAll(ambientBlockPattern)) {
|
|
1500
|
+
const head = match[1];
|
|
1501
|
+
const start = match.index + match[0].indexOf(head);
|
|
1502
|
+
if (start < blankedUntil)
|
|
1503
|
+
continue;
|
|
1504
|
+
const open = match.index + match[0].length - 1;
|
|
1505
|
+
const close = matchingDelimiter(source, open, "{", "}");
|
|
1506
|
+
const end = close < 0 ? source.length : close + 1;
|
|
1507
|
+
const label = head.replace(/\s+/gu, " ");
|
|
1508
|
+
const declaredModule = /^(?:export\s+)?declare\s+module\s+["'](.+)["']$/u.exec(label);
|
|
1509
|
+
if (declaredModule && ownModules.has(declaredModule[1]) && close >= 0) {
|
|
1510
|
+
// The kept body is swept again rather than left to this loop, because a
|
|
1511
|
+
// block nested on the same line as this one has no statement start in
|
|
1512
|
+
// front of it once the outer match has consumed the opening brace.
|
|
1513
|
+
text = `${text.slice(0, start)}${" ".repeat(open + 1 - start)}${excludeAmbientBlocks(text.slice(open + 1, close), warnings, ownModules)} ${text.slice(close + 1)}`;
|
|
1514
|
+
blankedUntil = close + 1;
|
|
1515
|
+
continue;
|
|
1516
|
+
}
|
|
1517
|
+
warnings.push(close < 0
|
|
1518
|
+
? `Ambient '${label}' block has an unclosed body, so it and the rest of the declaration file were ignored`
|
|
1519
|
+
: `Ambient '${label}' block is outside the VelarScript declaration bridge and its declarations were ignored`);
|
|
1520
|
+
text = text.slice(0, start) + " ".repeat(end - start) + text.slice(end);
|
|
1521
|
+
blankedUntil = end;
|
|
1522
|
+
}
|
|
1523
|
+
return text;
|
|
1524
|
+
}
|
|
1408
1525
|
function matchingDelimiter(source, start, open, close) {
|
|
1409
1526
|
let depth = 0;
|
|
1410
1527
|
let quote = "";
|
|
@@ -1466,19 +1583,110 @@ function topLevelTerminator(source, start, terminator) {
|
|
|
1466
1583
|
}
|
|
1467
1584
|
return -1;
|
|
1468
1585
|
}
|
|
1586
|
+
/**
|
|
1587
|
+
* Text that starts a fresh interface, object type, or class member. A body may
|
|
1588
|
+
* terminate its members with semicolons, with newlines, or with a mix of the
|
|
1589
|
+
* two, so a newline ends a member only when what follows opens a new one
|
|
1590
|
+
* rather than continuing the type that is being written.
|
|
1591
|
+
*/
|
|
1592
|
+
const memberHeadPattern = /^(?:(?:readonly|public|private|protected|static|override|abstract|declare)\s+)*(?:new\s*\(|constructor\s*\(|(?:get|set)\s+[A-Za-z_$][\w$]*\s*\(|\[|\(|<|[A-Za-z_$][\w$]*\s*\??\s*[:(<]|["'][^"'\r\n]*["']\s*\??\s*[:(])/u;
|
|
1593
|
+
/**
|
|
1594
|
+
* Reports whether a member that reads as `pending` is plainly unfinished, so a
|
|
1595
|
+
* newline inside it is a wrap rather than a terminator.
|
|
1596
|
+
*/
|
|
1597
|
+
function memberContinues(pending) {
|
|
1598
|
+
const trimmed = pending.trimEnd();
|
|
1599
|
+
if (!trimmed)
|
|
1600
|
+
return true;
|
|
1601
|
+
if (trimmed.endsWith("=>"))
|
|
1602
|
+
return true;
|
|
1603
|
+
if (/\b(?:extends|keyof|typeof|infer|in|is|new|readonly)$/u.test(trimmed))
|
|
1604
|
+
return true;
|
|
1605
|
+
return /[:,|&=<([{?+\-.]$/u.test(trimmed);
|
|
1606
|
+
}
|
|
1607
|
+
/**
|
|
1608
|
+
* Splits a declaration body into members on its real terminators: a top-level
|
|
1609
|
+
* `;` or `,`, or a top-level newline that separates a finished member from the
|
|
1610
|
+
* head of the next one. Choosing one separator for the whole body glues the
|
|
1611
|
+
* member after a semicolon-less method onto it, which deletes that member from
|
|
1612
|
+
* the package's contract without a word.
|
|
1613
|
+
*/
|
|
1469
1614
|
function splitFields(source) {
|
|
1470
|
-
const
|
|
1471
|
-
|
|
1615
|
+
const output = [];
|
|
1616
|
+
let start = 0;
|
|
1617
|
+
let angle = 0;
|
|
1618
|
+
let round = 0;
|
|
1619
|
+
let square = 0;
|
|
1620
|
+
let brace = 0;
|
|
1621
|
+
let quote = "";
|
|
1622
|
+
const take = (end) => {
|
|
1623
|
+
const member = source.slice(start, end).trim();
|
|
1624
|
+
if (member)
|
|
1625
|
+
output.push(member);
|
|
1626
|
+
start = end + 1;
|
|
1627
|
+
};
|
|
1628
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
1629
|
+
const character = source[index];
|
|
1630
|
+
if (quote) {
|
|
1631
|
+
if (character === "\\")
|
|
1632
|
+
index += 1;
|
|
1633
|
+
else if (character === quote)
|
|
1634
|
+
quote = "";
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
if (character === "\"" || character === "'" || character === "`")
|
|
1638
|
+
quote = character;
|
|
1639
|
+
else if (character === "<")
|
|
1640
|
+
angle += 1;
|
|
1641
|
+
else if (character === ">")
|
|
1642
|
+
angle = Math.max(0, angle - 1);
|
|
1643
|
+
else if (character === "(")
|
|
1644
|
+
round += 1;
|
|
1645
|
+
else if (character === ")")
|
|
1646
|
+
round = Math.max(0, round - 1);
|
|
1647
|
+
else if (character === "[")
|
|
1648
|
+
square += 1;
|
|
1649
|
+
else if (character === "]")
|
|
1650
|
+
square = Math.max(0, square - 1);
|
|
1651
|
+
else if (character === "{")
|
|
1652
|
+
brace += 1;
|
|
1653
|
+
else if (character === "}")
|
|
1654
|
+
brace = Math.max(0, brace - 1);
|
|
1655
|
+
else if (angle === 0 && round === 0 && square === 0 && brace === 0) {
|
|
1656
|
+
if (character === ";" || character === ",")
|
|
1657
|
+
take(index);
|
|
1658
|
+
else if (character === "\n"
|
|
1659
|
+
&& !memberContinues(source.slice(start, index))
|
|
1660
|
+
&& memberHeadPattern.test(source.slice(index + 1).trimStart())) {
|
|
1661
|
+
take(index);
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
const last = source.slice(start).trim();
|
|
1666
|
+
if (last)
|
|
1667
|
+
output.push(last);
|
|
1668
|
+
return output;
|
|
1472
1669
|
}
|
|
1473
1670
|
function splitTopLevel(source, separator) {
|
|
1474
1671
|
const output = [];
|
|
1475
1672
|
let start = 0;
|
|
1476
1673
|
let angle = 0;
|
|
1477
1674
|
let round = 0;
|
|
1675
|
+
let square = 0;
|
|
1478
1676
|
let brace = 0;
|
|
1677
|
+
let quote = "";
|
|
1479
1678
|
for (let index = 0; index < source.length; index += 1) {
|
|
1480
1679
|
const character = source[index];
|
|
1481
|
-
if (
|
|
1680
|
+
if (quote) {
|
|
1681
|
+
if (character === "\\")
|
|
1682
|
+
index += 1;
|
|
1683
|
+
else if (character === quote)
|
|
1684
|
+
quote = "";
|
|
1685
|
+
continue;
|
|
1686
|
+
}
|
|
1687
|
+
if (character === "\"" || character === "'" || character === "`")
|
|
1688
|
+
quote = character;
|
|
1689
|
+
else if (character === "<")
|
|
1482
1690
|
angle += 1;
|
|
1483
1691
|
else if (character === ">")
|
|
1484
1692
|
angle = Math.max(0, angle - 1);
|
|
@@ -1486,11 +1694,15 @@ function splitTopLevel(source, separator) {
|
|
|
1486
1694
|
round += 1;
|
|
1487
1695
|
else if (character === ")")
|
|
1488
1696
|
round = Math.max(0, round - 1);
|
|
1697
|
+
else if (character === "[")
|
|
1698
|
+
square += 1;
|
|
1699
|
+
else if (character === "]")
|
|
1700
|
+
square = Math.max(0, square - 1);
|
|
1489
1701
|
else if (character === "{")
|
|
1490
1702
|
brace += 1;
|
|
1491
1703
|
else if (character === "}")
|
|
1492
1704
|
brace = Math.max(0, brace - 1);
|
|
1493
|
-
else if (character === separator && angle === 0 && round === 0 && brace === 0) {
|
|
1705
|
+
else if (character === separator && angle === 0 && round === 0 && square === 0 && brace === 0) {
|
|
1494
1706
|
output.push(source.slice(start, index).trim());
|
|
1495
1707
|
start = index + 1;
|
|
1496
1708
|
}
|