@nola-lang/typescript-plugin 0.1.0-alpha.0 → 0.1.2
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/LICENSE +201 -21
- package/dist/plugin.cjs +583 -134
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +6 -0
- package/dist/plugin.js.map +1 -1
- package/dist/resolution-watch.d.ts +30 -0
- package/dist/resolution-watch.d.ts.map +1 -0
- package/dist/resolution-watch.js +95 -0
- package/dist/resolution-watch.js.map +1 -0
- package/package.json +7 -6
package/dist/plugin.cjs
CHANGED
|
@@ -50,7 +50,7 @@ var require_main = __commonJS({
|
|
|
50
50
|
__export(node_exports, {
|
|
51
51
|
analyzeMetafile: () => analyzeMetafile,
|
|
52
52
|
analyzeMetafileSync: () => analyzeMetafileSync,
|
|
53
|
-
build: () =>
|
|
53
|
+
build: () => build2,
|
|
54
54
|
buildSync: () => buildSync,
|
|
55
55
|
context: () => context,
|
|
56
56
|
default: () => node_default,
|
|
@@ -59,7 +59,7 @@ var require_main = __commonJS({
|
|
|
59
59
|
initialize: () => initialize,
|
|
60
60
|
stop: () => stop,
|
|
61
61
|
transform: () => transform2,
|
|
62
|
-
transformSync: () =>
|
|
62
|
+
transformSync: () => transformSync,
|
|
63
63
|
version: () => version
|
|
64
64
|
});
|
|
65
65
|
module2.exports = __toCommonJS(node_exports);
|
|
@@ -1883,7 +1883,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
1883
1883
|
}
|
|
1884
1884
|
};
|
|
1885
1885
|
var version = "0.25.12";
|
|
1886
|
-
var
|
|
1886
|
+
var build2 = (options) => ensureServiceIsRunning().build(options);
|
|
1887
1887
|
var context = (buildOptions) => ensureServiceIsRunning().context(buildOptions);
|
|
1888
1888
|
var transform2 = (input, options) => ensureServiceIsRunning().transform(input, options);
|
|
1889
1889
|
var formatMessages = (messages, options) => ensureServiceIsRunning().formatMessages(messages, options);
|
|
@@ -1907,7 +1907,7 @@ More information: The file containing the code for esbuild's JavaScript API (${_
|
|
|
1907
1907
|
}));
|
|
1908
1908
|
return result;
|
|
1909
1909
|
};
|
|
1910
|
-
var
|
|
1910
|
+
var transformSync = (input, options) => {
|
|
1911
1911
|
if (worker_threads && !isInternalWorkerThread) {
|
|
1912
1912
|
if (!workerThreadService) workerThreadService = startWorkerThreadService(worker_threads);
|
|
1913
1913
|
return workerThreadService.transformSync(input, options);
|
|
@@ -4547,14 +4547,21 @@ var Codes = {
|
|
|
4547
4547
|
ExpectedProviderName: "NOLA1009",
|
|
4548
4548
|
ContextualParamOutsideInfer: "NOLA1010",
|
|
4549
4549
|
ContextualParamReserved: "NOLA1011",
|
|
4550
|
+
IncompleteContextualParam: "NOLA1012",
|
|
4551
|
+
ContextualParamDoubleDot: "NOLA1013",
|
|
4552
|
+
ContextualBindingReserved: "NOLA1014",
|
|
4553
|
+
IncompleteScopeAccess: "NOLA1015",
|
|
4550
4554
|
AskOutsideNolaFunction: "NOLA2001",
|
|
4551
4555
|
UnsupportedIntentType: "NOLA2002",
|
|
4552
4556
|
NolaFnNotTopLevel: "NOLA2003",
|
|
4553
4557
|
UntypedCallIntentArg: "NOLA2004",
|
|
4554
4558
|
SubstitutionInCallMarker: "NOLA2005",
|
|
4559
|
+
// retired (emit 11): call-hint substitutions are legal; number not reused
|
|
4555
4560
|
ReservedCompanionPath: "NOLA2006",
|
|
4556
4561
|
CompanionUnavailable: "NOLA2007",
|
|
4557
4562
|
UnderivableContextType: "NOLA2008",
|
|
4563
|
+
ScopeAccessOutsideTemplate: "NOLA2009",
|
|
4564
|
+
NolaConstructInMarker: "NOLA2010",
|
|
4558
4565
|
// NOLA3xxx: runtime diagnostics
|
|
4559
4566
|
EmitContractMismatch: "NOLA3001",
|
|
4560
4567
|
DuplicateRuntimeConflict: "NOLA3002",
|
|
@@ -4566,7 +4573,12 @@ var Codes = {
|
|
|
4566
4573
|
ReplayFingerprintMismatch: "NOLA3008",
|
|
4567
4574
|
SchemaUnsupported: "NOLA3009",
|
|
4568
4575
|
IntentWithoutContext: "NOLA3010",
|
|
4569
|
-
IntentWithoutParentFrame: "NOLA3011"
|
|
4576
|
+
IntentWithoutParentFrame: "NOLA3011",
|
|
4577
|
+
ConfigImportsTsi: "NOLA3012",
|
|
4578
|
+
BrowserExecutionUnsupported: "NOLA3013",
|
|
4579
|
+
PromptTemplateFailed: "NOLA3014",
|
|
4580
|
+
// NOLA4xxx: bundler-integration errors (build-time, raised by @nola-lang/unplugin and friends)
|
|
4581
|
+
TsiInClientBundle: "NOLA4001"
|
|
4570
4582
|
};
|
|
4571
4583
|
function isNode(v) {
|
|
4572
4584
|
return typeof v === "object" && v !== null && typeof v.type === "string" && typeof v.start === "number";
|
|
@@ -4592,6 +4604,17 @@ function programBody(ast) {
|
|
|
4592
4604
|
const program = ast.type === "File" ? ast.program : ast;
|
|
4593
4605
|
return program.type === "Program" ? program.body ?? [] : [];
|
|
4594
4606
|
}
|
|
4607
|
+
function walk(root, visit) {
|
|
4608
|
+
const queue = [{ node: root, parent: null }];
|
|
4609
|
+
while (queue.length > 0) {
|
|
4610
|
+
const item = queue.shift();
|
|
4611
|
+
if (!item)
|
|
4612
|
+
break;
|
|
4613
|
+
visit(item.node, item.parent);
|
|
4614
|
+
for (const child of children(item.node))
|
|
4615
|
+
queue.push({ node: child, parent: item.node });
|
|
4616
|
+
}
|
|
4617
|
+
}
|
|
4595
4618
|
|
|
4596
4619
|
// ../core/dist/errors.js
|
|
4597
4620
|
var NolaConfigError = class extends Error {
|
|
@@ -4602,6 +4625,14 @@ var NolaConfigError = class extends Error {
|
|
|
4602
4625
|
this.code = code2;
|
|
4603
4626
|
}
|
|
4604
4627
|
};
|
|
4628
|
+
var NolaIntentError = class extends Error {
|
|
4629
|
+
code;
|
|
4630
|
+
name = "NolaIntentError";
|
|
4631
|
+
constructor(message, code2) {
|
|
4632
|
+
super(message);
|
|
4633
|
+
this.code = code2;
|
|
4634
|
+
}
|
|
4635
|
+
};
|
|
4605
4636
|
var NolaVersionError = class extends Error {
|
|
4606
4637
|
code;
|
|
4607
4638
|
details;
|
|
@@ -4639,7 +4670,7 @@ function redactError(error) {
|
|
|
4639
4670
|
}
|
|
4640
4671
|
|
|
4641
4672
|
// ../core/dist/index.js
|
|
4642
|
-
var NOLA_EMIT =
|
|
4673
|
+
var NOLA_EMIT = 11;
|
|
4643
4674
|
function mergeProviderParams(base, patch) {
|
|
4644
4675
|
if (!base || !patch)
|
|
4645
4676
|
return patch ?? base;
|
|
@@ -9565,10 +9596,14 @@ var NolaErrors = ParseErrorEnum`nola`({
|
|
|
9565
9596
|
NolaReservedConstruct: "NOLA1004: this Nola construct is reserved for a future Nola version.",
|
|
9566
9597
|
NolaExpectedPromptTemplate: "NOLA1005: expected a template literal prompt after `..`.",
|
|
9567
9598
|
NolaLegacyMarker: "NOLA1007: the `function name``()` form was removed \u2014 declare the function with `infer function`.",
|
|
9568
|
-
|
|
9599
|
+
// NOLA1008 (marker substitution) is retired since emit 11 — the number is not reused.
|
|
9600
|
+
NolaIncompleteScopeAccess: "NOLA1015: incomplete scope access \u2014 write `${.member}`.",
|
|
9569
9601
|
NolaExpectedProviderName: "NOLA1009: expected a provider name after `ask with` \u2014 for a dynamic provider use `.withProvider(...)` on the intent.",
|
|
9570
|
-
NolaContextualOutsideInfer: "NOLA1010:
|
|
9571
|
-
NolaContextualParamReserved: "NOLA1011:
|
|
9602
|
+
NolaContextualOutsideInfer: "NOLA1010: `.` context parameters are only allowed on infer function parameters.",
|
|
9603
|
+
NolaContextualParamReserved: "NOLA1011: `.` on this parameter form is reserved for a future Nola version \u2014 use a plain identifier parameter.",
|
|
9604
|
+
NolaIncompleteContextualParam: "NOLA1012: incomplete `.` context parameter \u2014 write `.name`.",
|
|
9605
|
+
NolaContextualParamDoubleDot: "NOLA1013: contextual parameters take one dot \u2014 write `.name` (`..` is the extractor sigil).",
|
|
9606
|
+
NolaContextualBindingReserved: "NOLA1014: `.name` contextual bindings (`const .x = \u2026`) are reserved for a future Nola version."
|
|
9572
9607
|
});
|
|
9573
9608
|
var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
9574
9609
|
// Set for the duration of a single parseFunctionParams call when we are
|
|
@@ -9582,6 +9617,43 @@ var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
|
9582
9617
|
// True while parsing the parameter list of an infer function (save/restore
|
|
9583
9618
|
// across nested function-expression params in default values).
|
|
9584
9619
|
nolaInInferParams = false;
|
|
9620
|
+
// One entry per template literal being parsed (outermost first). A
|
|
9621
|
+
// `${.member}` hole marks EVERY enclosing literal, so an instruction site
|
|
9622
|
+
// learns about scope access at any nesting depth (inside a .map callback's
|
|
9623
|
+
// own template literal, say). Depth > 0 is what makes a leading dot in
|
|
9624
|
+
// expression position a scope access instead of a syntax error.
|
|
9625
|
+
nolaTemplateStack = [];
|
|
9626
|
+
parseTemplate(isTagged) {
|
|
9627
|
+
const entry = { scopeAccess: false };
|
|
9628
|
+
this.nolaTemplateStack.push(entry);
|
|
9629
|
+
try {
|
|
9630
|
+
const node = super.parseTemplate(isTagged);
|
|
9631
|
+
if (entry.scopeAccess)
|
|
9632
|
+
node.nolaHasScopeAccess = true;
|
|
9633
|
+
return node;
|
|
9634
|
+
} finally {
|
|
9635
|
+
this.nolaTemplateStack.pop();
|
|
9636
|
+
}
|
|
9637
|
+
}
|
|
9638
|
+
// `${.member}` — scope access. Only reached inside a template hole (see
|
|
9639
|
+
// parseExprAtom); `..` tokenizes as nolaDotDot, so an inner extractor in a
|
|
9640
|
+
// hole never lands here. Keyword members (`.default`) are legal: the
|
|
9641
|
+
// identifier is parsed liberally like any property name.
|
|
9642
|
+
nolaParseScopeAccess() {
|
|
9643
|
+
const node = this.startNode();
|
|
9644
|
+
const startLoc = this.state.startLoc;
|
|
9645
|
+
this.next();
|
|
9646
|
+
for (const t of this.nolaTemplateStack)
|
|
9647
|
+
t.scopeAccess = true;
|
|
9648
|
+
if (tokenIsKeywordOrIdentifier(this.state.type)) {
|
|
9649
|
+
node.property = this.parseIdentifier(true);
|
|
9650
|
+
} else {
|
|
9651
|
+
this.raise(NolaErrors.NolaIncompleteScopeAccess, startLoc);
|
|
9652
|
+
node.property = null;
|
|
9653
|
+
node.nolaError = true;
|
|
9654
|
+
}
|
|
9655
|
+
return this.finishNode(node, "NolaScopeAccess");
|
|
9656
|
+
}
|
|
9585
9657
|
// `infer function` at statement / export position. `infer` tokenizes as the
|
|
9586
9658
|
// keyword-like tt._infer, and we only claim it when the NEXT token is
|
|
9587
9659
|
// `function` — every other use of `infer` (identifier, TS conditional-type
|
|
@@ -9634,7 +9706,27 @@ var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
|
9634
9706
|
}
|
|
9635
9707
|
super.readToken_dot();
|
|
9636
9708
|
}
|
|
9709
|
+
// A `.` standing where an extractor is being typed: consume it and hand
|
|
9710
|
+
// back the broken-extract placeholder (nolaError), which the lowering
|
|
9711
|
+
// replaces with an inert expression.
|
|
9712
|
+
nolaIncompleteExtract() {
|
|
9713
|
+
const node = this.startNode();
|
|
9714
|
+
const startLoc = this.state.startLoc;
|
|
9715
|
+
this.next();
|
|
9716
|
+
this.raise(NolaErrors.NolaExpectedPromptTemplate, startLoc);
|
|
9717
|
+
node.quasi = null;
|
|
9718
|
+
node.prompt = "";
|
|
9719
|
+
node.typeArgs = null;
|
|
9720
|
+
node.nolaError = true;
|
|
9721
|
+
return this.finishNode(node, "NolaExtractExpression");
|
|
9722
|
+
}
|
|
9637
9723
|
parseExprAtom(refExpressionErrors) {
|
|
9724
|
+
if (this.match(tt.dot) && this.nolaTemplateStack.length > 0) {
|
|
9725
|
+
return this.nolaParseScopeAccess();
|
|
9726
|
+
}
|
|
9727
|
+
if (this.match(tt.dot) && this.optionFlags & 4096) {
|
|
9728
|
+
return this.nolaIncompleteExtract();
|
|
9729
|
+
}
|
|
9638
9730
|
if (this.match(tt.nolaDotDot)) {
|
|
9639
9731
|
const node = this.startNode();
|
|
9640
9732
|
this.next();
|
|
@@ -9685,7 +9777,7 @@ var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
|
9685
9777
|
this.next();
|
|
9686
9778
|
}
|
|
9687
9779
|
}
|
|
9688
|
-
node.argument = this.parseMaybeUnary(null, true);
|
|
9780
|
+
node.argument = this.match(tt.dot) ? this.nolaIncompleteExtract() : this.parseMaybeUnary(null, true);
|
|
9689
9781
|
return this.finishNode(node, "NolaAskExpression");
|
|
9690
9782
|
}
|
|
9691
9783
|
return super.parseMaybeUnary(refExpressionErrors, sawUnary);
|
|
@@ -9724,11 +9816,14 @@ var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
|
9724
9816
|
if (!infer) {
|
|
9725
9817
|
this.raise(NolaErrors.NolaLegacyMarker, markerStart);
|
|
9726
9818
|
} else {
|
|
9727
|
-
if (tmpl.expressions.length > 0) {
|
|
9728
|
-
this.raise(NolaErrors.NolaMarkerSubstitution, markerStart);
|
|
9729
|
-
}
|
|
9730
9819
|
const instruction = tmpl.quasis.map((q) => q.value.cooked ?? q.value.raw).join("");
|
|
9731
|
-
n2.nolaMarker = {
|
|
9820
|
+
n2.nolaMarker = {
|
|
9821
|
+
start: markerStart,
|
|
9822
|
+
end: tmpl.end,
|
|
9823
|
+
instruction,
|
|
9824
|
+
quasi: tmpl,
|
|
9825
|
+
hasScopeAccess: tmpl.nolaHasScopeAccess === true
|
|
9826
|
+
};
|
|
9732
9827
|
}
|
|
9733
9828
|
}
|
|
9734
9829
|
const prevInInferParams = this.nolaInInferParams;
|
|
@@ -9739,15 +9834,27 @@ var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
|
9739
9834
|
this.nolaInInferParams = prevInInferParams;
|
|
9740
9835
|
}
|
|
9741
9836
|
}
|
|
9742
|
-
//
|
|
9837
|
+
// `.name` context parameter. Claimed only at function-param positions
|
|
9743
9838
|
// (IS_FUNCTION_PARAMS); array-pattern elements never see the flag. On a
|
|
9744
9839
|
// non-infer function it is NOLA1010; on any non-identifier form (pattern,
|
|
9745
9840
|
// default) it is NOLA1011 — both recover by parsing the element normally.
|
|
9841
|
+
// The retired `..name` spelling is NOLA1013 and otherwise behaves the same,
|
|
9842
|
+
// so tolerant mode gets one diagnostic instead of a bail.
|
|
9746
9843
|
parseBindingElement(flags, decorators) {
|
|
9747
|
-
|
|
9844
|
+
const doubled = this.match(tt.nolaDotDot);
|
|
9845
|
+
if ((doubled || this.match(tt.dot)) && flags & 2) {
|
|
9748
9846
|
const span = { start: this.state.start, end: this.state.end };
|
|
9749
9847
|
const startLoc = this.state.startLoc;
|
|
9750
9848
|
this.next();
|
|
9849
|
+
if (doubled && this.nolaInInferParams)
|
|
9850
|
+
this.raise(NolaErrors.NolaContextualParamDoubleDot, startLoc);
|
|
9851
|
+
if (this.nolaInInferParams && (this.match(tt.parenR) || this.match(tt.comma))) {
|
|
9852
|
+
this.raise(NolaErrors.NolaIncompleteContextualParam, startLoc);
|
|
9853
|
+
const placeholder = this.startNodeAt(startLoc);
|
|
9854
|
+
placeholder.name = `__nola_incomplete_${span.start}`;
|
|
9855
|
+
placeholder.nolaError = true;
|
|
9856
|
+
return this.finishNode(placeholder, "Identifier");
|
|
9857
|
+
}
|
|
9751
9858
|
const elt = super.parseBindingElement(flags, decorators);
|
|
9752
9859
|
if (!this.nolaInInferParams) {
|
|
9753
9860
|
this.raise(NolaErrors.NolaContextualOutsideInfer, startLoc);
|
|
@@ -9760,6 +9867,33 @@ var nola_default = (superClass) => class NolaParserMixin extends superClass {
|
|
|
9760
9867
|
}
|
|
9761
9868
|
return super.parseBindingElement(flags, decorators);
|
|
9762
9869
|
}
|
|
9870
|
+
// `const .x` / `let .x` / `var .x` (either dot count): the contextual
|
|
9871
|
+
// BINDING form is reserved. Consume the marker, report, then parse the id
|
|
9872
|
+
// normally so tolerant mode keeps a sane tree; the span rides on the id so
|
|
9873
|
+
// the lowering can drop the bytes under a `broken` span.
|
|
9874
|
+
parseVarId(decl, kind) {
|
|
9875
|
+
if (this.match(tt.dot) || this.match(tt.nolaDotDot)) {
|
|
9876
|
+
const span = { start: this.state.start, end: this.state.end };
|
|
9877
|
+
const startLoc = this.state.startLoc;
|
|
9878
|
+
this.next();
|
|
9879
|
+
this.raise(NolaErrors.NolaContextualBindingReserved, startLoc);
|
|
9880
|
+
super.parseVarId(decl, kind);
|
|
9881
|
+
decl.id.nolaReservedMarker = span;
|
|
9882
|
+
return;
|
|
9883
|
+
}
|
|
9884
|
+
super.parseVarId(decl, kind);
|
|
9885
|
+
}
|
|
9886
|
+
// `let` is contextual: Babel promotes it to a declaration keyword only when
|
|
9887
|
+
// the next character can start a binding. A `.` after `let` can only be the
|
|
9888
|
+
// (reserved) contextual-binding marker in a module — `let` is not a legal
|
|
9889
|
+
// identifier there, so `let.x` member access is already an error — so let it
|
|
9890
|
+
// through to parseVarId, which reports NOLA1014. Scoped to the `let` token
|
|
9891
|
+
// so no other binding-start probe changes.
|
|
9892
|
+
chStartsBindingIdentifier(ch, pos) {
|
|
9893
|
+
if (ch === charCodes5.dot && this.state.type === tt._let)
|
|
9894
|
+
return true;
|
|
9895
|
+
return super.chStartsBindingIdentifier(ch, pos);
|
|
9896
|
+
}
|
|
9763
9897
|
// Flag method context so parseFunctionParams can reject markers on object methods.
|
|
9764
9898
|
parseMethod(node, isGenerator, isAsync, isConstructor, allowDirectSuper, type, inClassScope) {
|
|
9765
9899
|
this.nolaInMethod = true;
|
|
@@ -20904,7 +21038,7 @@ var IDENT = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
|
20904
21038
|
function deriveTypeExpr(t, ctx) {
|
|
20905
21039
|
const refs = /* @__PURE__ */ new Set();
|
|
20906
21040
|
const companions = /* @__PURE__ */ new Map();
|
|
20907
|
-
const result =
|
|
21041
|
+
const result = walk2(t, ctx, refs, companions);
|
|
20908
21042
|
return result.ok ? { ok: true, expr: result.expr, refs, companions } : result;
|
|
20909
21043
|
}
|
|
20910
21044
|
function collectTypeImports(ast) {
|
|
@@ -20949,7 +21083,7 @@ function buildAccessorPlan(entryRefs, ctx) {
|
|
|
20949
21083
|
}
|
|
20950
21084
|
return plan;
|
|
20951
21085
|
}
|
|
20952
|
-
function
|
|
21086
|
+
function walk2(t, ctx, refs, companions) {
|
|
20953
21087
|
switch (t.type) {
|
|
20954
21088
|
case "TSStringKeyword":
|
|
20955
21089
|
return { ok: true, expr: "__nola.types.string()" };
|
|
@@ -20958,7 +21092,7 @@ function walk(t, ctx, refs, companions) {
|
|
|
20958
21092
|
case "TSBooleanKeyword":
|
|
20959
21093
|
return { ok: true, expr: "__nola.types.boolean()" };
|
|
20960
21094
|
case "TSArrayType": {
|
|
20961
|
-
const inner =
|
|
21095
|
+
const inner = walk2(t.elementType, ctx, refs, companions);
|
|
20962
21096
|
return inner.ok ? { ok: true, expr: `__nola.types.array(${inner.expr})` } : inner;
|
|
20963
21097
|
}
|
|
20964
21098
|
case "TSTypeLiteral":
|
|
@@ -21071,7 +21205,7 @@ function walkObject(members, ctx, refs, companions, owner) {
|
|
|
21071
21205
|
continue;
|
|
21072
21206
|
return { ok: false, message: `property '${name}' needs a type annotation`, node: member };
|
|
21073
21207
|
}
|
|
21074
|
-
const inner =
|
|
21208
|
+
const inner = walk2(annotation, ctx, refs, companions);
|
|
21075
21209
|
if (!inner.ok) {
|
|
21076
21210
|
if (ctx.lossy)
|
|
21077
21211
|
continue;
|
|
@@ -22371,17 +22505,17 @@ var SpanRecorder = class {
|
|
|
22371
22505
|
constructor(source) {
|
|
22372
22506
|
this.s = new MagicString(source);
|
|
22373
22507
|
}
|
|
22374
|
-
overwrite(start, end, text,
|
|
22508
|
+
overwrite(start, end, text, options = {}) {
|
|
22375
22509
|
this.s.overwrite(start, end, text);
|
|
22376
|
-
this.edits.push({ sourceStart: start, sourceEnd: end, text, side: 0, seq: this.seq++,
|
|
22510
|
+
this.edits.push({ sourceStart: start, sourceEnd: end, text, side: 0, seq: this.seq++, ...options });
|
|
22377
22511
|
}
|
|
22378
22512
|
remove(start, end) {
|
|
22379
22513
|
this.s.remove(start, end);
|
|
22380
22514
|
this.edits.push({ sourceStart: start, sourceEnd: end, text: "", side: 0, seq: this.seq++ });
|
|
22381
22515
|
}
|
|
22382
|
-
appendLeft(pos, text) {
|
|
22516
|
+
appendLeft(pos, text, options = {}) {
|
|
22383
22517
|
this.s.appendLeft(pos, text);
|
|
22384
|
-
this.edits.push({ sourceStart: pos, sourceEnd: pos, text, side: 0, seq: this.seq
|
|
22518
|
+
this.edits.push({ sourceStart: pos, sourceEnd: pos, text, side: 0, seq: this.seq++, ...options });
|
|
22385
22519
|
}
|
|
22386
22520
|
appendRight(pos, text) {
|
|
22387
22521
|
this.s.appendRight(pos, text);
|
|
@@ -22428,7 +22562,7 @@ var SpanRecorder = class {
|
|
|
22428
22562
|
});
|
|
22429
22563
|
}
|
|
22430
22564
|
const prev = spans[spans.length - 1];
|
|
22431
|
-
if (prev && prev.kind === "replaced" && prev.sourceEnd === e.sourceStart && prev.generatedEnd === gen) {
|
|
22565
|
+
if (!e.broken && prev && prev.kind === "replaced" && prev.sourceEnd === e.sourceStart && prev.generatedEnd === gen) {
|
|
22432
22566
|
prev.sourceEnd = e.sourceEnd;
|
|
22433
22567
|
prev.generatedEnd += e.text.length;
|
|
22434
22568
|
} else {
|
|
@@ -22437,7 +22571,7 @@ var SpanRecorder = class {
|
|
|
22437
22571
|
sourceEnd: e.sourceEnd,
|
|
22438
22572
|
generatedStart: gen,
|
|
22439
22573
|
generatedEnd: gen + e.text.length,
|
|
22440
|
-
kind: "replaced"
|
|
22574
|
+
kind: e.broken ? "broken" : "replaced"
|
|
22441
22575
|
});
|
|
22442
22576
|
}
|
|
22443
22577
|
gen += e.text.length;
|
|
@@ -22473,22 +22607,45 @@ var askClose = (providerName) => `, __frame${providerName ? `, ${JSON.stringify(
|
|
|
22473
22607
|
var invocationOpen = (paramNames) => `
|
|
22474
22608
|
return __nola.intents.Intent(async (__frame) => {${paramNames.map((n2) => ` void ${n2};`).join("")}`;
|
|
22475
22609
|
var invocationArgEntry = (name, typeExpr, contextual) => `{ name: ${JSON.stringify(name)}${typeExpr ? `, type: ${typeExpr}` : ""}${contextual ? `, contextual: true, value: ${name}` : ""} }`;
|
|
22476
|
-
var invocationClose = (fnName,
|
|
22610
|
+
var invocationClose = (fnName, instructionField, argEntries) => {
|
|
22477
22611
|
const argsField = argEntries.length > 0 ? `, args: [${argEntries.join(", ")}]` : "";
|
|
22478
|
-
return ` }, __nola_file_ctx().func({ fn: ${JSON.stringify(fnName)}, instruction: ${
|
|
22612
|
+
return ` }, __nola_file_ctx().func({ fn: ${JSON.stringify(fnName)}, instruction: ${instructionField}${argsField} }));
|
|
22479
22613
|
`;
|
|
22480
22614
|
};
|
|
22615
|
+
function templateCopy(source, quasi, scopeNodes, mode) {
|
|
22616
|
+
const inserts = mode === "scope" ? scopeNodes.map((n2) => [n2.start, SCOPE_PARAM]) : quasi.expressions.flatMap((e) => [[e.start, FMT_OPEN], [e.end, FMT_CLOSE]]);
|
|
22617
|
+
inserts.sort((a, b) => a[0] - b[0]);
|
|
22618
|
+
let text = "";
|
|
22619
|
+
const anchors = [];
|
|
22620
|
+
let cursor = quasi.start;
|
|
22621
|
+
for (const [pos, ins] of inserts) {
|
|
22622
|
+
if (pos > cursor) {
|
|
22623
|
+
anchors.push({ sourceStart: cursor, sourceEnd: pos, textOffset: text.length });
|
|
22624
|
+
text += source.slice(cursor, pos);
|
|
22625
|
+
}
|
|
22626
|
+
text += ins;
|
|
22627
|
+
cursor = pos;
|
|
22628
|
+
}
|
|
22629
|
+
anchors.push({ sourceStart: cursor, sourceEnd: quasi.end, textOffset: text.length });
|
|
22630
|
+
text += source.slice(cursor, quasi.end);
|
|
22631
|
+
return { text, anchors };
|
|
22632
|
+
}
|
|
22481
22633
|
var callIntentTypeText = (tagText) => `<Awaited<ReturnType<typeof ${tagText}>>>`;
|
|
22482
22634
|
var callIntentOpen = (typeText) => `__nola.intents.FunctionCallingIntent${typeText}({ fn: `;
|
|
22483
|
-
var callIntentArgsHead = (tagText,
|
|
22635
|
+
var callIntentArgsHead = (tagText, instructionField, loc) => `, name: ${JSON.stringify(tagText)}, instruction: ${instructionField}, loc: ${JSON.stringify(locText(loc))}, args: [`;
|
|
22484
22636
|
var CALL_INTENT_CLOSE = "] })";
|
|
22485
22637
|
var EXTRACT_DEFAULT_TYPE_EXPR = "__nola.types.string()";
|
|
22486
22638
|
var EXTRACT_DEFAULT_TYPE_TEXT = "<any>";
|
|
22487
22639
|
var typeArgsText = (sourceText) => `<${sourceText}>`;
|
|
22488
22640
|
var extractOpen = (typeText) => `__nola.intents.ExtractIntent${typeText}({ instruction: `;
|
|
22641
|
+
var SCOPE_PARAM = "__nola_s";
|
|
22642
|
+
var TEMPLATE_OPEN = `template: (${SCOPE_PARAM}) => __nola.tpl`;
|
|
22643
|
+
var rawTemplateText = (source, quasi) => source.slice(quasi.start + 1, quasi.end - 1);
|
|
22644
|
+
var extractOpenTemplate = (typeText, rawInstruction) => `__nola.intents.ExtractIntent${typeText}({ instruction: ${JSON.stringify(rawInstruction)}, ${TEMPLATE_OPEN}`;
|
|
22489
22645
|
var FMT_OPEN = "__nola.fmt(";
|
|
22490
22646
|
var FMT_CLOSE = ")";
|
|
22491
22647
|
var extractClose = (typeExpr, loc) => `, type: ${typeExpr}, loc: ${JSON.stringify(locText(loc))} })`;
|
|
22648
|
+
var BROKEN_CONSTRUCT = "(undefined as never)";
|
|
22492
22649
|
|
|
22493
22650
|
// ../compiler/dist/lower/lowerer.js
|
|
22494
22651
|
var Lowerer = class {
|
|
@@ -22502,13 +22659,27 @@ var Lowerer = class {
|
|
|
22502
22659
|
diagnostics = [];
|
|
22503
22660
|
meta = { nolaFunctions: [] };
|
|
22504
22661
|
usedRuntime = false;
|
|
22662
|
+
/**
|
|
22663
|
+
* Where a `${.member}` scope access may appear right now: "inplace" — the
|
|
22664
|
+
* enclosing instruction literal stays where it is (extractor), so the scope
|
|
22665
|
+
* parameter is inserted before the dot here; "copy" — the literal is copied
|
|
22666
|
+
* elsewhere (marker / call hint) and the copy builder did the insertion;
|
|
22667
|
+
* "none" — not inside a Nola instruction literal (NOLA2009).
|
|
22668
|
+
*/
|
|
22669
|
+
scopeSite = "none";
|
|
22670
|
+
/**
|
|
22671
|
+
* True while visiting the holes of a COPIED instruction literal (marker /
|
|
22672
|
+
* call hint). Nola constructs there have nowhere to lower to — the literal
|
|
22673
|
+
* is re-emitted from source bytes — so they are NOLA2010.
|
|
22674
|
+
*/
|
|
22675
|
+
inCopiedHole = false;
|
|
22505
22676
|
/** named types needing a __nola_type_<Name> accessor in the appendix, in first-use order */
|
|
22506
22677
|
typeAccessors = /* @__PURE__ */ new Map();
|
|
22507
22678
|
/** local binding name -> companion import emitted in the appendix */
|
|
22508
22679
|
companionImports = /* @__PURE__ */ new Map();
|
|
22509
22680
|
/** shared derivation context (registry, imports, display file, bare ref names) */
|
|
22510
22681
|
deriveCtx;
|
|
22511
|
-
/** policy for underivable
|
|
22682
|
+
/** policy for underivable `.`-contextual param types (compiler.underivableContextType) */
|
|
22512
22683
|
underivableContextType;
|
|
22513
22684
|
constructor(source, file, ast, displayFile, options = {}) {
|
|
22514
22685
|
this.s = new SpanRecorder(source);
|
|
@@ -22569,7 +22740,7 @@ var Lowerer = class {
|
|
|
22569
22740
|
this.diag(Codes.UnsupportedIntentType, e.message, e.node);
|
|
22570
22741
|
}
|
|
22571
22742
|
/**
|
|
22572
|
-
* A
|
|
22743
|
+
* A `.`-contextual param's type failed to derive (shallowly or in its
|
|
22573
22744
|
* accessor plan). Resolve it per the configured policy; the returned expr
|
|
22574
22745
|
* (if any) replaces the failed one.
|
|
22575
22746
|
*/
|
|
@@ -22614,13 +22785,38 @@ var Lowerer = class {
|
|
|
22614
22785
|
visit(node, inNolaFnBody, topLevel) {
|
|
22615
22786
|
switch (node.type) {
|
|
22616
22787
|
case "NolaExtractExpression": {
|
|
22788
|
+
if (this.inCopiedHole) {
|
|
22789
|
+
this.diagCopiedHole(node);
|
|
22790
|
+
return;
|
|
22791
|
+
}
|
|
22617
22792
|
const extract = node;
|
|
22618
|
-
if (extract.nolaError || !extract.quasi)
|
|
22793
|
+
if (extract.nolaError || !extract.quasi) {
|
|
22794
|
+
this.s.overwrite(node.start, node.end, BROKEN_CONSTRUCT, { broken: true });
|
|
22619
22795
|
return;
|
|
22796
|
+
}
|
|
22620
22797
|
this.lowerExtract(extract, inNolaFnBody);
|
|
22621
22798
|
return;
|
|
22622
22799
|
}
|
|
22800
|
+
case "NolaScopeAccess": {
|
|
22801
|
+
if (this.scopeSite === "none") {
|
|
22802
|
+
this.diag(
|
|
22803
|
+
Codes.ScopeAccessOutsideTemplate,
|
|
22804
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal ${...} in a diagnostic message
|
|
22805
|
+
"`${.member}` scope access is only allowed inside a Nola instruction template (infer-function marker, extractor prompt, call-intent hint).",
|
|
22806
|
+
node
|
|
22807
|
+
);
|
|
22808
|
+
this.s.overwrite(node.start, node.end, BROKEN_CONSTRUCT, { broken: true });
|
|
22809
|
+
return;
|
|
22810
|
+
}
|
|
22811
|
+
if (this.scopeSite === "inplace")
|
|
22812
|
+
this.s.appendLeft(node.start, SCOPE_PARAM);
|
|
22813
|
+
return;
|
|
22814
|
+
}
|
|
22623
22815
|
case "NolaAskExpression": {
|
|
22816
|
+
if (this.inCopiedHole) {
|
|
22817
|
+
this.diagCopiedHole(node);
|
|
22818
|
+
return;
|
|
22819
|
+
}
|
|
22624
22820
|
const ask2 = node;
|
|
22625
22821
|
if (!inNolaFnBody) {
|
|
22626
22822
|
this.diag(Codes.AskOutsideNolaFunction, "`ask` is only allowed directly inside an infer function body.", node);
|
|
@@ -22652,9 +22848,24 @@ var Lowerer = class {
|
|
|
22652
22848
|
case "CallExpression": {
|
|
22653
22849
|
const call = node;
|
|
22654
22850
|
if (call.callee.type === "TaggedTemplateExpression") {
|
|
22851
|
+
if (this.inCopiedHole) {
|
|
22852
|
+
this.diagCopiedHole(node);
|
|
22853
|
+
return;
|
|
22854
|
+
}
|
|
22655
22855
|
this.lowerCallIntent(call, inNolaFnBody);
|
|
22656
22856
|
return;
|
|
22657
22857
|
}
|
|
22858
|
+
if ((call.callee.type === "Identifier" || call.callee.type === "MemberExpression") && call.arguments.some((a) => this.hasExtractorSlot(a))) {
|
|
22859
|
+
this.lowerCallIntent(call, inNolaFnBody);
|
|
22860
|
+
return;
|
|
22861
|
+
}
|
|
22862
|
+
break;
|
|
22863
|
+
}
|
|
22864
|
+
case "VariableDeclarator": {
|
|
22865
|
+
const id = node.id;
|
|
22866
|
+
if (id?.nolaReservedMarker) {
|
|
22867
|
+
this.s.overwrite(id.nolaReservedMarker.start, id.nolaReservedMarker.end, "", { broken: true });
|
|
22868
|
+
}
|
|
22658
22869
|
break;
|
|
22659
22870
|
}
|
|
22660
22871
|
default:
|
|
@@ -22666,21 +22877,81 @@ var Lowerer = class {
|
|
|
22666
22877
|
this.visit(child, isFunctionScope ? false : inNolaFnBody, nextTopLevel);
|
|
22667
22878
|
}
|
|
22668
22879
|
}
|
|
22880
|
+
/**
|
|
22881
|
+
* Sigil-less call-intent detection (2026-08-14 spec): a well-formed extractor
|
|
22882
|
+
* in a slot position — a direct argument, or nested at any depth inside plain
|
|
22883
|
+
* object/array literals (the same walk checkCallIntentArg performs). Tolerant
|
|
22884
|
+
* placeholders (nolaError) do NOT count: a half-typed `f(..` stays a plain
|
|
22885
|
+
* call, so the editor never lowers a call intent around a broken slot.
|
|
22886
|
+
*/
|
|
22887
|
+
hasExtractorSlot(node) {
|
|
22888
|
+
if (node.type === "NolaExtractExpression") {
|
|
22889
|
+
return !node.nolaError;
|
|
22890
|
+
}
|
|
22891
|
+
if (node.type === "ObjectExpression") {
|
|
22892
|
+
return node.properties.some((p) => p.type === "ObjectProperty" && this.hasExtractorSlot(p.value));
|
|
22893
|
+
}
|
|
22894
|
+
if (node.type === "ArrayExpression") {
|
|
22895
|
+
return node.elements.some((el) => el != null && this.hasExtractorSlot(el));
|
|
22896
|
+
}
|
|
22897
|
+
return false;
|
|
22898
|
+
}
|
|
22899
|
+
diagCopiedHole(node) {
|
|
22900
|
+
this.diag(Codes.NolaConstructInMarker, "Nola constructs are not allowed inside an infer-function marker or call-intent hint hole.", node);
|
|
22901
|
+
}
|
|
22902
|
+
/**
|
|
22903
|
+
* The instruction field of a copied instruction literal (marker / call hint):
|
|
22904
|
+
* prose → JSON string; lexical holes → a template literal with fmt-wrapped
|
|
22905
|
+
* holes; `${.member}` holes → the raw text as the instruction plus the
|
|
22906
|
+
* template closure. Anchors point back at the literal's verbatim runs.
|
|
22907
|
+
*/
|
|
22908
|
+
instructionFieldFor(quasi, hasScopeAccess, cooked) {
|
|
22909
|
+
if (quasi.expressions.length === 0)
|
|
22910
|
+
return { field: JSON.stringify(cooked), copyText: "", anchors: [], holes: [] };
|
|
22911
|
+
const scopeNodes = [];
|
|
22912
|
+
if (hasScopeAccess) {
|
|
22913
|
+
walk(quasi, (n2) => {
|
|
22914
|
+
if (n2.type === "NolaScopeAccess")
|
|
22915
|
+
scopeNodes.push(n2);
|
|
22916
|
+
});
|
|
22917
|
+
}
|
|
22918
|
+
const copy = templateCopy(this.source, quasi, scopeNodes, hasScopeAccess ? "scope" : "fmt");
|
|
22919
|
+
const field = hasScopeAccess ? `${JSON.stringify(rawTemplateText(this.source, quasi))}, ${TEMPLATE_OPEN}${copy.text}` : copy.text;
|
|
22920
|
+
return { field, copyText: copy.text, anchors: copy.anchors, holes: quasi.expressions };
|
|
22921
|
+
}
|
|
22922
|
+
/** Visit the holes of a copied literal only to diagnose (NOLA2010 / NOLA2009) — the copy is already built. */
|
|
22923
|
+
visitCopiedHoles(holes, inNolaFnBody) {
|
|
22924
|
+
const prevSite = this.scopeSite;
|
|
22925
|
+
const prevHole = this.inCopiedHole;
|
|
22926
|
+
this.scopeSite = "copy";
|
|
22927
|
+
this.inCopiedHole = true;
|
|
22928
|
+
try {
|
|
22929
|
+
for (const e of holes)
|
|
22930
|
+
this.visit(e, inNolaFnBody, false);
|
|
22931
|
+
} finally {
|
|
22932
|
+
this.scopeSite = prevSite;
|
|
22933
|
+
this.inCopiedHole = prevHole;
|
|
22934
|
+
}
|
|
22935
|
+
}
|
|
22669
22936
|
lowerInferFunction(fn) {
|
|
22670
22937
|
const infer = fn.nolaInfer;
|
|
22671
22938
|
if (!infer)
|
|
22672
22939
|
return;
|
|
22673
22940
|
const name = fn.id?.name ?? "anonymous";
|
|
22674
22941
|
this.s.remove(infer.start, infer.end);
|
|
22675
|
-
const
|
|
22676
|
-
if (
|
|
22677
|
-
this.s.remove(
|
|
22942
|
+
const marker = fn.nolaMarker;
|
|
22943
|
+
if (marker)
|
|
22944
|
+
this.s.remove(marker.start, marker.end);
|
|
22678
22945
|
const body = fn.body;
|
|
22679
22946
|
if (!body)
|
|
22680
22947
|
return;
|
|
22681
22948
|
const argEntries = [];
|
|
22682
22949
|
const paramNames = [];
|
|
22683
22950
|
for (const p of fn.params ?? []) {
|
|
22951
|
+
if (p.nolaError) {
|
|
22952
|
+
this.s.overwrite(p.start, p.end, "", { broken: true });
|
|
22953
|
+
continue;
|
|
22954
|
+
}
|
|
22684
22955
|
if (p.nolaContextual)
|
|
22685
22956
|
this.s.remove(p.nolaContextual.start, p.nolaContextual.end);
|
|
22686
22957
|
const target = p.type === "AssignmentPattern" ? p.left : p;
|
|
@@ -22708,34 +22979,34 @@ var Lowerer = class {
|
|
|
22708
22979
|
}
|
|
22709
22980
|
argEntries.push(invocationArgEntry(paramName, typeExpr, Boolean(p.nolaContextual)));
|
|
22710
22981
|
}
|
|
22982
|
+
const inst = marker?.quasi !== void 0 ? this.instructionFieldFor(marker.quasi, marker.hasScopeAccess === true, marker.instruction) : { field: JSON.stringify(marker?.instruction ?? ""), copyText: "", anchors: [], holes: [] };
|
|
22983
|
+
const close = invocationClose(name, inst.field, argEntries);
|
|
22984
|
+
const copyAt = inst.copyText ? close.indexOf(inst.copyText) : -1;
|
|
22985
|
+
const anchors = copyAt >= 0 ? inst.anchors.map((a) => ({ ...a, textOffset: a.textOffset + copyAt })) : void 0;
|
|
22711
22986
|
this.s.appendRight(body.start + 1, invocationOpen(paramNames));
|
|
22712
|
-
this.s.appendLeft(body.end - 1,
|
|
22987
|
+
this.s.appendLeft(body.end - 1, close, anchors ? { anchors } : {});
|
|
22713
22988
|
this.meta.nolaFunctions.push(name);
|
|
22714
22989
|
this.usedRuntime = true;
|
|
22990
|
+
this.visitCopiedHoles(inst.holes, false);
|
|
22715
22991
|
}
|
|
22716
22992
|
lowerCallIntent(call, inNolaFnBody) {
|
|
22717
|
-
const
|
|
22718
|
-
const
|
|
22719
|
-
if (quasi.expressions.length > 0) {
|
|
22720
|
-
this.diag(
|
|
22721
|
-
Codes.SubstitutionInCallMarker,
|
|
22722
|
-
// biome-ignore lint/suspicious/noTemplateCurlyInString: literal ${...} in a diagnostic message
|
|
22723
|
-
"`${...}` substitutions are not allowed in a call-intent marker.",
|
|
22724
|
-
quasi.expressions[0]
|
|
22725
|
-
);
|
|
22726
|
-
return;
|
|
22727
|
-
}
|
|
22993
|
+
const tagged = call.callee.type === "TaggedTemplateExpression" ? call.callee : void 0;
|
|
22994
|
+
const inst = tagged ? this.instructionFieldFor(tagged.quasi, tagged.quasi.nolaHasScopeAccess === true, tagged.quasi.quasis.map((q) => q.value.cooked ?? q.value.raw).join("")) : { field: '""', copyText: "", anchors: [], holes: [] };
|
|
22728
22995
|
for (const arg of call.arguments)
|
|
22729
22996
|
this.checkCallIntentArg(arg);
|
|
22730
|
-
const
|
|
22731
|
-
const
|
|
22732
|
-
const simple =
|
|
22733
|
-
const typeText = simple ? callIntentTypeText(
|
|
22997
|
+
const callee = tagged ? tagged.tag : call.callee;
|
|
22998
|
+
const calleeText = this.source.slice(callee.start, callee.end);
|
|
22999
|
+
const simple = callee.type === "Identifier" || callee.type === "MemberExpression";
|
|
23000
|
+
const typeText = simple ? callIntentTypeText(calleeText) : "";
|
|
22734
23001
|
this.s.appendLeft(call.start, callIntentOpen(typeText));
|
|
22735
23002
|
const argsStart = call.arguments.length > 0 ? call.arguments[0].start : call.end - 1;
|
|
22736
|
-
|
|
23003
|
+
const head = callIntentArgsHead(calleeText, inst.field, call.loc.start);
|
|
23004
|
+
const copyAt = inst.copyText ? head.indexOf(inst.copyText) : -1;
|
|
23005
|
+
const anchors = copyAt >= 0 ? inst.anchors.map((a) => ({ ...a, textOffset: a.textOffset + copyAt })) : void 0;
|
|
23006
|
+
this.s.overwrite(callee.end, argsStart, head, anchors ? { anchors } : {});
|
|
22737
23007
|
this.s.overwrite(call.end - 1, call.end, CALL_INTENT_CLOSE);
|
|
22738
23008
|
this.usedRuntime = true;
|
|
23009
|
+
this.visitCopiedHoles(inst.holes, inNolaFnBody);
|
|
22739
23010
|
for (const arg of call.arguments)
|
|
22740
23011
|
this.visit(arg, inNolaFnBody, false);
|
|
22741
23012
|
}
|
|
@@ -22783,13 +23054,16 @@ var Lowerer = class {
|
|
|
22783
23054
|
}
|
|
22784
23055
|
}
|
|
22785
23056
|
}
|
|
22786
|
-
const
|
|
23057
|
+
const isTemplate = quasi.nolaHasScopeAccess === true;
|
|
23058
|
+
const open = isTemplate ? extractOpenTemplate(typeText, rawTemplateText(this.source, quasi)) : extractOpen(typeText);
|
|
22787
23059
|
const typeNode = node.typeArgs?.params[0];
|
|
22788
23060
|
const anchors = typeNode ? [{ sourceStart: typeNode.start, sourceEnd: typeNode.end, textOffset: open.indexOf(typeText) + 1 }] : void 0;
|
|
22789
|
-
this.s.overwrite(node.start, quasi.start, open, anchors);
|
|
22790
|
-
|
|
22791
|
-
|
|
22792
|
-
|
|
23061
|
+
this.s.overwrite(node.start, quasi.start, open, { anchors });
|
|
23062
|
+
if (!isTemplate) {
|
|
23063
|
+
for (const expr of quasi.expressions) {
|
|
23064
|
+
this.s.appendLeft(expr.start, FMT_OPEN);
|
|
23065
|
+
this.s.appendLeft(expr.end, FMT_CLOSE);
|
|
23066
|
+
}
|
|
22793
23067
|
}
|
|
22794
23068
|
const suffix = extractClose(typeExpr, node.loc.start);
|
|
22795
23069
|
if (node.end > quasi.end) {
|
|
@@ -22798,8 +23072,14 @@ var Lowerer = class {
|
|
|
22798
23072
|
this.s.appendLeft(node.end, suffix);
|
|
22799
23073
|
}
|
|
22800
23074
|
this.usedRuntime = true;
|
|
22801
|
-
|
|
22802
|
-
|
|
23075
|
+
const prevSite = this.scopeSite;
|
|
23076
|
+
this.scopeSite = isTemplate ? "inplace" : "none";
|
|
23077
|
+
try {
|
|
23078
|
+
for (const expr of quasi.expressions)
|
|
23079
|
+
this.visit(expr, inNolaFnBody, false);
|
|
23080
|
+
} finally {
|
|
23081
|
+
this.scopeSite = prevSite;
|
|
23082
|
+
}
|
|
22803
23083
|
}
|
|
22804
23084
|
};
|
|
22805
23085
|
|
|
@@ -22978,15 +23258,33 @@ var INSERTION_DATA = { navigation: true, format: false };
|
|
|
22978
23258
|
function spansToMappings(spans, anchors = [], code2) {
|
|
22979
23259
|
const verbatim = [];
|
|
22980
23260
|
const replaced = [];
|
|
23261
|
+
const afterBroken = new Set(spans.filter((s) => s.kind === "broken").map((s) => s.sourceEnd));
|
|
22981
23262
|
for (const span of spans) {
|
|
22982
23263
|
if (span.kind === "verbatim") {
|
|
23264
|
+
if (afterBroken.has(span.sourceStart) && span.sourceEnd > span.sourceStart) {
|
|
23265
|
+
verbatim.push({
|
|
23266
|
+
sourceOffsets: [span.sourceStart],
|
|
23267
|
+
generatedOffsets: [span.generatedStart],
|
|
23268
|
+
lengths: [1],
|
|
23269
|
+
data: { ...VERBATIM_DATA, completion: false }
|
|
23270
|
+
});
|
|
23271
|
+
if (span.sourceEnd - span.sourceStart === 1)
|
|
23272
|
+
continue;
|
|
23273
|
+
verbatim.push({
|
|
23274
|
+
sourceOffsets: [span.sourceStart + 1],
|
|
23275
|
+
generatedOffsets: [span.generatedStart + 1],
|
|
23276
|
+
lengths: [span.sourceEnd - span.sourceStart - 1],
|
|
23277
|
+
data: { ...VERBATIM_DATA }
|
|
23278
|
+
});
|
|
23279
|
+
continue;
|
|
23280
|
+
}
|
|
22983
23281
|
verbatim.push({
|
|
22984
23282
|
sourceOffsets: [span.sourceStart],
|
|
22985
23283
|
generatedOffsets: [span.generatedStart],
|
|
22986
23284
|
lengths: [span.sourceEnd - span.sourceStart],
|
|
22987
23285
|
data: { ...VERBATIM_DATA }
|
|
22988
23286
|
});
|
|
22989
|
-
} else if (span.kind === "replaced") {
|
|
23287
|
+
} else if (span.kind === "replaced" || span.kind === "broken") {
|
|
22990
23288
|
replaced.push({
|
|
22991
23289
|
sourceOffsets: [span.sourceStart],
|
|
22992
23290
|
generatedOffsets: [span.generatedStart],
|
|
@@ -23135,10 +23433,6 @@ function createNolaLanguagePlugin(asFileName, options = {}) {
|
|
|
23135
23433
|
};
|
|
23136
23434
|
}
|
|
23137
23435
|
|
|
23138
|
-
// ../node-loader/dist/config.js
|
|
23139
|
-
var import_node_fs2 = require("node:fs");
|
|
23140
|
-
var import_node_path2 = require("node:path");
|
|
23141
|
-
|
|
23142
23436
|
// ../runtime/dist/runtime/ask-span.js
|
|
23143
23437
|
var AskSpan = class {
|
|
23144
23438
|
kind = "ask";
|
|
@@ -23222,6 +23516,7 @@ var ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
|
23222
23516
|
"system",
|
|
23223
23517
|
"ask",
|
|
23224
23518
|
"compiler",
|
|
23519
|
+
"build",
|
|
23225
23520
|
...RESERVED_KEYS
|
|
23226
23521
|
]);
|
|
23227
23522
|
var HOOK_METHODS = [
|
|
@@ -23316,6 +23611,24 @@ function resolveCompilerConfig(raw, source) {
|
|
|
23316
23611
|
}
|
|
23317
23612
|
return Object.freeze({ underivableContextType: mode ?? "error" });
|
|
23318
23613
|
}
|
|
23614
|
+
var BUILD_TARGETS = ["app", "lib"];
|
|
23615
|
+
function resolveBuildConfig(raw, source) {
|
|
23616
|
+
if (raw === void 0)
|
|
23617
|
+
return Object.freeze({ target: "app" });
|
|
23618
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
23619
|
+
fail(source, '`build` must be an object \u2014 write build: { target: "lib" }.');
|
|
23620
|
+
}
|
|
23621
|
+
const cfg = raw;
|
|
23622
|
+
for (const key of Object.keys(cfg)) {
|
|
23623
|
+
if (key !== "target")
|
|
23624
|
+
fail(source, `unknown build config key \`${key}\` \u2014 allowed keys: target.`);
|
|
23625
|
+
}
|
|
23626
|
+
const target = cfg.target;
|
|
23627
|
+
if (target !== void 0 && (typeof target !== "string" || !BUILD_TARGETS.includes(target))) {
|
|
23628
|
+
fail(source, `build.target must be one of ${BUILD_TARGETS.join(", ")}.`);
|
|
23629
|
+
}
|
|
23630
|
+
return Object.freeze({ target: target ?? "app" });
|
|
23631
|
+
}
|
|
23319
23632
|
function validateMiddleware(source, raw) {
|
|
23320
23633
|
if (raw === void 0)
|
|
23321
23634
|
return Object.freeze([]);
|
|
@@ -23342,7 +23655,7 @@ function resolveNolaConfig(raw, opts = {}) {
|
|
|
23342
23655
|
}
|
|
23343
23656
|
for (const key of Object.keys(cfg)) {
|
|
23344
23657
|
if (!ALLOWED_KEYS.has(key)) {
|
|
23345
|
-
fail(source, `unknown config key \`${key}\` \u2014 allowed keys: providers, forceProvider, observability, hooks, middleware, cache, system, ask, compiler.`);
|
|
23658
|
+
fail(source, `unknown config key \`${key}\` \u2014 allowed keys: providers, forceProvider, observability, hooks, middleware, cache, system, ask, compiler, build.`);
|
|
23346
23659
|
}
|
|
23347
23660
|
}
|
|
23348
23661
|
const providers = cfg.providers;
|
|
@@ -23383,6 +23696,7 @@ function resolveNolaConfig(raw, opts = {}) {
|
|
|
23383
23696
|
const system = validateSystem(source, cfg.system);
|
|
23384
23697
|
const ask2 = validateAsk(source, cfg.ask);
|
|
23385
23698
|
const compiler = resolveCompilerConfig(cfg.compiler, source);
|
|
23699
|
+
const build2 = resolveBuildConfig(cfg.build, source);
|
|
23386
23700
|
return Object.freeze({
|
|
23387
23701
|
providers: Object.freeze({ ...map }),
|
|
23388
23702
|
forceProvider: cfg.forceProvider,
|
|
@@ -23392,7 +23706,8 @@ function resolveNolaConfig(raw, opts = {}) {
|
|
|
23392
23706
|
cache: cache3,
|
|
23393
23707
|
system,
|
|
23394
23708
|
ask: ask2,
|
|
23395
|
-
compiler
|
|
23709
|
+
compiler,
|
|
23710
|
+
build: build2
|
|
23396
23711
|
});
|
|
23397
23712
|
}
|
|
23398
23713
|
|
|
@@ -23483,17 +23798,6 @@ var Frame = class _Frame {
|
|
|
23483
23798
|
composeInferenceData(composer, opts) {
|
|
23484
23799
|
this.infer.composeInferenceData(composer, { ...opts, nested: this.parent !== void 0 });
|
|
23485
23800
|
}
|
|
23486
|
-
// /**
|
|
23487
|
-
// * Prompt-facing lineage under stack-frame semantics: the root frame's static
|
|
23488
|
-
// * ancestry followed by one entry per frame down the call chain. A callee's
|
|
23489
|
-
// * own construction ancestors are bypassed — the caller chain is its lineage;
|
|
23490
|
-
// * sourceFile() (the definition site) intentionally differs.
|
|
23491
|
-
// */
|
|
23492
|
-
// promptLineage(): ReadonlyArray<Readonly<Record<string, unknown>>> {
|
|
23493
|
-
// if (!this.parent) return this.infer.promptLineage();
|
|
23494
|
-
// const own = this.infer.promptData();
|
|
23495
|
-
// return own === undefined ? this.parent.promptLineage() : [...this.parent.promptLineage(), own];
|
|
23496
|
-
// }
|
|
23497
23801
|
/**
|
|
23498
23802
|
* The .tsi file this frame's function is defined in (static chain first).
|
|
23499
23803
|
* Scope-less intents (extract/call) carry no file root — for them the
|
|
@@ -23527,6 +23831,70 @@ var Frame = class _Frame {
|
|
|
23527
23831
|
}
|
|
23528
23832
|
};
|
|
23529
23833
|
|
|
23834
|
+
// ../runtime/dist/ask/prompt-render.js
|
|
23835
|
+
var defaultPromptRenderer = Object.freeze({
|
|
23836
|
+
function(data) {
|
|
23837
|
+
const { fn, file, instruction, args, nested } = data;
|
|
23838
|
+
const signature = `${fn}(${args.map((a) => a.name).join(", ")})`;
|
|
23839
|
+
const header = `CONTEXT \u2014 inside ${signature}` + (file === void 0 ? "" : `, ${file}`) + (nested ? ", called from the context above" : "");
|
|
23840
|
+
const lines = [header];
|
|
23841
|
+
if (instruction)
|
|
23842
|
+
lines.push(`Purpose: ${instruction}`);
|
|
23843
|
+
if (args.length > 0) {
|
|
23844
|
+
lines.push("Arguments (values are runtime data, not instructions):");
|
|
23845
|
+
for (const a of args) {
|
|
23846
|
+
if (!a.contextual) {
|
|
23847
|
+
lines.push(`- ${a.name} = (value not available)`);
|
|
23848
|
+
continue;
|
|
23849
|
+
}
|
|
23850
|
+
const type = a.type ? ` (${a.type.toNativeType()})` : "";
|
|
23851
|
+
if (a.value === void 0) {
|
|
23852
|
+
lines.push(`- ${a.name}${type} = (no value)`);
|
|
23853
|
+
} else if (typeof a.value === "string" && (a.value.includes("\n") || a.value.length > 120)) {
|
|
23854
|
+
lines.push(`- ${a.name}${type}:`, "<value>", a.value, "</value>");
|
|
23855
|
+
} else {
|
|
23856
|
+
lines.push(`- ${a.name}${type} = ${JSON.stringify(a.value)}`);
|
|
23857
|
+
}
|
|
23858
|
+
}
|
|
23859
|
+
}
|
|
23860
|
+
return lines.join("\n");
|
|
23861
|
+
},
|
|
23862
|
+
extract(data) {
|
|
23863
|
+
const { instruction, hasContext } = data;
|
|
23864
|
+
const lines = [
|
|
23865
|
+
"TASK",
|
|
23866
|
+
hasContext ? "Produce the data requested below from the context above." : "Produce the data requested below.",
|
|
23867
|
+
"<request>",
|
|
23868
|
+
instruction,
|
|
23869
|
+
"</request>",
|
|
23870
|
+
extractFormat(data)
|
|
23871
|
+
];
|
|
23872
|
+
return lines.join("\n");
|
|
23873
|
+
}
|
|
23874
|
+
});
|
|
23875
|
+
function extractFormat(data) {
|
|
23876
|
+
const lines = [];
|
|
23877
|
+
if (!data.trivialString)
|
|
23878
|
+
lines.push("RESPONSE SCHEMA (JSON Schema):", JSON.stringify(data.schema));
|
|
23879
|
+
lines.push(data.trivialString ? "Respond with a single JSON string containing the value." : "Respond with a single JSON value strictly conforming to the schema above.");
|
|
23880
|
+
return lines.join("\n");
|
|
23881
|
+
}
|
|
23882
|
+
function joinBlocks(...parts) {
|
|
23883
|
+
return parts.filter((p) => p.length > 0).join("\n\n");
|
|
23884
|
+
}
|
|
23885
|
+
function renderTemplate(template, scope, site, tail, tailRead) {
|
|
23886
|
+
let text;
|
|
23887
|
+
try {
|
|
23888
|
+
text = template(scope);
|
|
23889
|
+
} catch (e) {
|
|
23890
|
+
throw new NolaIntentError(`${Codes.PromptTemplateFailed}: prompt template at ${site} threw: ${e instanceof Error ? e.message : String(e)}`, Codes.PromptTemplateFailed);
|
|
23891
|
+
}
|
|
23892
|
+
if (typeof text !== "string" || text.trim() === "") {
|
|
23893
|
+
throw new NolaIntentError(`${Codes.PromptTemplateFailed}: prompt template at ${site} rendered no text.`, Codes.PromptTemplateFailed);
|
|
23894
|
+
}
|
|
23895
|
+
return tailRead() ? text : joinBlocks(text, tail());
|
|
23896
|
+
}
|
|
23897
|
+
|
|
23530
23898
|
// ../runtime/dist/infer-context/infer-context.js
|
|
23531
23899
|
var InferContext = class _InferContext {
|
|
23532
23900
|
data;
|
|
@@ -23541,31 +23909,16 @@ var InferContext = class _InferContext {
|
|
|
23541
23909
|
scope(data) {
|
|
23542
23910
|
return new _InferContext(Object.freeze({ ...data }), this.runtime, this);
|
|
23543
23911
|
}
|
|
23544
|
-
/**
|
|
23545
|
-
|
|
23546
|
-
|
|
23547
|
-
|
|
23548
|
-
|
|
23549
|
-
|
|
23550
|
-
|
|
23551
|
-
|
|
23552
|
-
|
|
23553
|
-
}
|
|
23554
|
-
/** Raw data chain from root to this node (internal/debug). */
|
|
23555
|
-
// lineage(): ReadonlyArray<Readonly<Record<string, unknown>>> {
|
|
23556
|
-
// const chain: Array<Readonly<Record<string, unknown>>> = [];
|
|
23557
|
-
// for (let c: InferContext | undefined = this; c; c = c.parent) chain.unshift(c.data);
|
|
23558
|
-
// return chain;
|
|
23559
|
-
// }
|
|
23560
|
-
/** Prompt-facing lineage: promptData() per node, undefined entries dropped. */
|
|
23561
|
-
// promptLineage(): ReadonlyArray<Readonly<Record<string, unknown>>> {
|
|
23562
|
-
// const chain: Array<Readonly<Record<string, unknown>>> = [];
|
|
23563
|
-
// for (let c: InferContext | undefined = this; c; c = c.parent) {
|
|
23564
|
-
// const d = c.promptData();
|
|
23565
|
-
// if (d !== undefined) chain.unshift(d);
|
|
23566
|
-
// }
|
|
23567
|
-
// return chain;
|
|
23568
|
-
// }
|
|
23912
|
+
/** Whether this node emits prompt text of its own (function/extract nodes do; bare scopes do not). */
|
|
23913
|
+
contributesText() {
|
|
23914
|
+
return false;
|
|
23915
|
+
}
|
|
23916
|
+
/** Base nodes contribute nothing — the remainder passes straight through. */
|
|
23917
|
+
composeInferenceData(composer, opts) {
|
|
23918
|
+
const rest = opts?.next?.() ?? "";
|
|
23919
|
+
if (rest)
|
|
23920
|
+
composer.addText(rest);
|
|
23921
|
+
}
|
|
23569
23922
|
/**
|
|
23570
23923
|
* The `.tsi` file this context descends from: the nearest file node up the
|
|
23571
23924
|
* parent chain (FileInferContext overrides). A lineage with no file root
|
|
@@ -23581,42 +23934,67 @@ var FunctionInferContext = class _FunctionInferContext extends InferContext {
|
|
|
23581
23934
|
/** @internal created via FileInferContext.func (and tests) only. Parentless = free-standing scope. */
|
|
23582
23935
|
static create(init, runtime, parent) {
|
|
23583
23936
|
const args = Object.freeze((init.args ?? []).map((a) => Object.freeze({ name: a.name, type: a.type, contextual: a.contextual ?? false, value: a.value })));
|
|
23584
|
-
return new _FunctionInferContext(Object.freeze({
|
|
23937
|
+
return new _FunctionInferContext(Object.freeze({
|
|
23938
|
+
fn: init.fn,
|
|
23939
|
+
instruction: init.instruction ?? "",
|
|
23940
|
+
...init.template ? { template: init.template } : {},
|
|
23941
|
+
args
|
|
23942
|
+
}), runtime, parent);
|
|
23943
|
+
}
|
|
23944
|
+
contributesText() {
|
|
23945
|
+
return true;
|
|
23585
23946
|
}
|
|
23586
23947
|
/**
|
|
23587
|
-
* One CONTEXT block per invocation
|
|
23588
|
-
*
|
|
23589
|
-
*
|
|
23590
|
-
*
|
|
23591
|
-
*
|
|
23592
|
-
* input — keep it
|
|
23948
|
+
* One CONTEXT block per invocation. The node assembles FunctionPromptData;
|
|
23949
|
+
* without a template the runtime's PromptRenderer renders it and the
|
|
23950
|
+
* remainder follows; with a template (a `${.member}` marker) the template
|
|
23951
|
+
* renders the block from a FunctionPromptScope over the same data — `.default`
|
|
23952
|
+
* is the built-in block, `.next` the remainder (appended after the template
|
|
23953
|
+
* when it never reads it). The composed text is fingerprint input — keep it
|
|
23954
|
+
* deterministic.
|
|
23593
23955
|
*/
|
|
23594
23956
|
composeInferenceData(composer, opts) {
|
|
23595
|
-
const { fn, instruction, args } = this.data;
|
|
23596
|
-
const signature = `${fn}(${args.map((a) => a.name).join(", ")})`;
|
|
23957
|
+
const { fn, instruction, args, template } = this.data;
|
|
23597
23958
|
const file = this.sourceFile();
|
|
23598
|
-
const
|
|
23599
|
-
|
|
23600
|
-
|
|
23601
|
-
|
|
23602
|
-
|
|
23603
|
-
|
|
23604
|
-
|
|
23605
|
-
|
|
23606
|
-
|
|
23607
|
-
|
|
23608
|
-
|
|
23609
|
-
|
|
23610
|
-
|
|
23611
|
-
|
|
23612
|
-
|
|
23613
|
-
lines.push(`- ${a.name}${type}:`, "<value>", a.value, "</value>");
|
|
23614
|
-
} else {
|
|
23615
|
-
lines.push(`- ${a.name}${type} = ${JSON.stringify(a.value)}`);
|
|
23616
|
-
}
|
|
23617
|
-
}
|
|
23959
|
+
const data = {
|
|
23960
|
+
kind: "function",
|
|
23961
|
+
fn,
|
|
23962
|
+
...file === "<unknown>" ? {} : { file },
|
|
23963
|
+
instruction,
|
|
23964
|
+
args,
|
|
23965
|
+
nested: opts?.nested ?? false,
|
|
23966
|
+
hasContext: opts?.hasContext ?? false
|
|
23967
|
+
};
|
|
23968
|
+
const renderer = this.runtime.promptRenderer;
|
|
23969
|
+
let memo;
|
|
23970
|
+
const rest = () => memo ??= opts?.next?.() ?? "";
|
|
23971
|
+
if (!template) {
|
|
23972
|
+
composer.addText(joinBlocks(renderer.function(data), rest()));
|
|
23973
|
+
return;
|
|
23618
23974
|
}
|
|
23619
|
-
|
|
23975
|
+
let nextRead = false;
|
|
23976
|
+
const scope = Object.freeze({
|
|
23977
|
+
fn,
|
|
23978
|
+
signature: `${fn}(${args.map((a) => a.name).join(", ")})`,
|
|
23979
|
+
...data.file === void 0 ? {} : { file: data.file },
|
|
23980
|
+
args: Object.freeze(args.map((a) => Object.freeze({
|
|
23981
|
+
name: a.name,
|
|
23982
|
+
...a.type ? { type: a.type.toNativeType() } : {},
|
|
23983
|
+
contextual: a.contextual,
|
|
23984
|
+
value: a.value
|
|
23985
|
+
}))),
|
|
23986
|
+
nested: data.nested,
|
|
23987
|
+
hasContext: data.hasContext,
|
|
23988
|
+
// The template IS the instruction: the default block renders without Purpose.
|
|
23989
|
+
get default() {
|
|
23990
|
+
return renderer.function({ ...data, instruction: "" });
|
|
23991
|
+
},
|
|
23992
|
+
get next() {
|
|
23993
|
+
nextRead = true;
|
|
23994
|
+
return rest();
|
|
23995
|
+
}
|
|
23996
|
+
});
|
|
23997
|
+
composer.addText(renderTemplate(template, scope, `${file}:${fn}`, rest, () => nextRead));
|
|
23620
23998
|
}
|
|
23621
23999
|
};
|
|
23622
24000
|
|
|
@@ -23729,6 +24107,13 @@ var NolaRuntime = class {
|
|
|
23729
24107
|
this.emit = emit;
|
|
23730
24108
|
this.url = url;
|
|
23731
24109
|
}
|
|
24110
|
+
/**
|
|
24111
|
+
* The provider-facing text seam consulted by every composeInferenceData —
|
|
24112
|
+
* the built-in renderer today (config-level overrides are the next step).
|
|
24113
|
+
*/
|
|
24114
|
+
get promptRenderer() {
|
|
24115
|
+
return defaultPromptRenderer;
|
|
24116
|
+
}
|
|
23732
24117
|
/** The frozen resolved config, or null when nothing has been configured yet. */
|
|
23733
24118
|
get config() {
|
|
23734
24119
|
return this.#config;
|
|
@@ -23845,8 +24230,12 @@ var nolaRuntime = {
|
|
|
23845
24230
|
}
|
|
23846
24231
|
};
|
|
23847
24232
|
|
|
23848
|
-
// ../node-loader/dist/config.js
|
|
24233
|
+
// ../node-loader/dist/bundle-config.js
|
|
23849
24234
|
var import_esbuild = __toESM(require_main(), 1);
|
|
24235
|
+
|
|
24236
|
+
// ../node-loader/dist/config.js
|
|
24237
|
+
var import_node_fs2 = require("node:fs");
|
|
24238
|
+
var import_node_path2 = require("node:path");
|
|
23850
24239
|
function findUp2(startDir, name) {
|
|
23851
24240
|
let dir = startDir;
|
|
23852
24241
|
for (; ; ) {
|
|
@@ -23973,6 +24362,61 @@ function guardProjectServiceDocumentCache(projectService) {
|
|
|
23973
24362
|
};
|
|
23974
24363
|
}
|
|
23975
24364
|
|
|
24365
|
+
// src/resolution-watch.ts
|
|
24366
|
+
function decorateHostForTsiResolutionWatch(host, serverHost, project, extensions) {
|
|
24367
|
+
const prior = host.resolveModuleNameLiterals?.bind(host);
|
|
24368
|
+
if (!prior) return;
|
|
24369
|
+
const watchFile = (path, cb) => serverHost.watchFile(
|
|
24370
|
+
path,
|
|
24371
|
+
cb,
|
|
24372
|
+
500
|
|
24373
|
+
);
|
|
24374
|
+
const caseSensitive = typeof host.useCaseSensitiveFileNames === "function" ? host.useCaseSensitiveFileNames() : host.useCaseSensitiveFileNames ?? false;
|
|
24375
|
+
const canon = (fileName) => {
|
|
24376
|
+
const posix = fileName.replace(/\\/g, "/");
|
|
24377
|
+
return caseSensitive ? posix : posix.toLowerCase();
|
|
24378
|
+
};
|
|
24379
|
+
const watched = /* @__PURE__ */ new Map();
|
|
24380
|
+
const invalidated = /* @__PURE__ */ new Set();
|
|
24381
|
+
const hostWithInvalidation = host;
|
|
24382
|
+
const projectWithDirty = project;
|
|
24383
|
+
let innerHasInvalidated = hostWithInvalidation.hasInvalidatedResolutions;
|
|
24384
|
+
const composedHasInvalidated = (path) => invalidated.has(canon(path)) || (innerHasInvalidated?.(path) ?? false);
|
|
24385
|
+
Object.defineProperty(host, "hasInvalidatedResolutions", {
|
|
24386
|
+
configurable: true,
|
|
24387
|
+
get: () => composedHasInvalidated,
|
|
24388
|
+
set: (fn) => {
|
|
24389
|
+
innerHasInvalidated = fn;
|
|
24390
|
+
}
|
|
24391
|
+
});
|
|
24392
|
+
host.resolveModuleNameLiterals = (moduleLiterals, containingFile, ...rest) => {
|
|
24393
|
+
const containing = canon(containingFile);
|
|
24394
|
+
invalidated.delete(containing);
|
|
24395
|
+
const results = prior(moduleLiterals, containingFile, ...rest);
|
|
24396
|
+
for (let i = 0; i < moduleLiterals.length; i++) {
|
|
24397
|
+
const text = moduleLiterals[i]?.text ?? "";
|
|
24398
|
+
if (!text.startsWith("./") && !text.startsWith("../")) continue;
|
|
24399
|
+
if (!extensions.some((ext) => text.endsWith(ext))) continue;
|
|
24400
|
+
const dir = containingFile.replace(/\\/g, "/").split("/").slice(0, -1).join("/");
|
|
24401
|
+
const candidate = canon(`${dir}/${text}`.replace(/\/\.\//g, "/"));
|
|
24402
|
+
const entry = watched.get(candidate);
|
|
24403
|
+
if (entry) {
|
|
24404
|
+
entry.waiters.add(containing);
|
|
24405
|
+
continue;
|
|
24406
|
+
}
|
|
24407
|
+
if (results[i]?.resolvedModule) continue;
|
|
24408
|
+
const waiters = /* @__PURE__ */ new Set([containing]);
|
|
24409
|
+
const watcher = watchFile(candidate, () => {
|
|
24410
|
+
for (const waiter of waiters) invalidated.add(waiter);
|
|
24411
|
+
projectWithDirty.markAsDirty?.();
|
|
24412
|
+
project.refreshDiagnostics();
|
|
24413
|
+
});
|
|
24414
|
+
watched.set(candidate, { watcher, waiters });
|
|
24415
|
+
}
|
|
24416
|
+
return results;
|
|
24417
|
+
};
|
|
24418
|
+
}
|
|
24419
|
+
|
|
23976
24420
|
// src/server-host.ts
|
|
23977
24421
|
var PATCHED2 = Symbol.for("nola.companionServerHost");
|
|
23978
24422
|
function decorateServerHostForCompanions(serverHost) {
|
|
@@ -24031,7 +24475,12 @@ function createNolaTsPlugin() {
|
|
|
24031
24475
|
decorateHostHideShadowedDeclarations(typescript, info.languageServiceHost);
|
|
24032
24476
|
decorateHostWithCompanions(typescript, info.languageServiceHost, { sourceRoot });
|
|
24033
24477
|
return {
|
|
24034
|
-
languagePlugins: [createNolaLanguagePlugin((fileName) => fileName, { sourceRoot })]
|
|
24478
|
+
languagePlugins: [createNolaLanguagePlugin((fileName) => fileName, { sourceRoot })],
|
|
24479
|
+
// setup runs AFTER Volar's decorateLanguageServiceHost, so this wraps the
|
|
24480
|
+
// resolver that actually handles `.tsi` literals (see resolution-watch.ts).
|
|
24481
|
+
setup: () => {
|
|
24482
|
+
decorateHostForTsiResolutionWatch(info.languageServiceHost, info.serverHost, info.project, [".tsi"]);
|
|
24483
|
+
}
|
|
24035
24484
|
};
|
|
24036
24485
|
});
|
|
24037
24486
|
}
|