acture-build-tier 1.1.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/LICENSE +190 -0
- package/README.md +112 -0
- package/dist/ast.cjs +146 -0
- package/dist/ast.cjs.map +1 -0
- package/dist/ast.d.cts +65 -0
- package/dist/ast.d.ts +65 -0
- package/dist/ast.js +111 -0
- package/dist/ast.js.map +1 -0
- package/dist/chunk-SWJN6WEL.js +138 -0
- package/dist/chunk-SWJN6WEL.js.map +1 -0
- package/dist/esbuild.cjs +163 -0
- package/dist/esbuild.cjs.map +1 -0
- package/dist/esbuild.d.cts +44 -0
- package/dist/esbuild.d.ts +44 -0
- package/dist/esbuild.js +24 -0
- package/dist/esbuild.js.map +1 -0
- package/dist/index.cjs +141 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +62 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/vite.cjs +157 -0
- package/dist/vite.cjs.map +1 -0
- package/dist/vite.d.cts +37 -0
- package/dist/vite.d.ts +37 -0
- package/dist/vite.js +22 -0
- package/dist/vite.js.map +1 -0
- package/package.json +85 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/transform.ts
|
|
4
|
+
var TIER_PRECEDENCE = /* @__PURE__ */ new Map([
|
|
5
|
+
["stable", 0],
|
|
6
|
+
["experimental", 1],
|
|
7
|
+
["deprecated", 2],
|
|
8
|
+
["internal", 3]
|
|
9
|
+
]);
|
|
10
|
+
function parseTierDirective(jsdocBody) {
|
|
11
|
+
let chosen;
|
|
12
|
+
const stripped = jsdocBody.replace(/^\s*\*\s?/gm, "");
|
|
13
|
+
const stableRe = /@stable\b/;
|
|
14
|
+
const experimentalRe = /@experimental\b/;
|
|
15
|
+
const internalRe = /@internal\b/;
|
|
16
|
+
const deprecatedRe = /@deprecated\b[ \t]*([^\n@]*)/;
|
|
17
|
+
if (stableRe.test(stripped)) chosen = take(chosen, { tier: "stable" });
|
|
18
|
+
if (experimentalRe.test(stripped)) chosen = take(chosen, { tier: "experimental" });
|
|
19
|
+
const depMatch = deprecatedRe.exec(stripped);
|
|
20
|
+
if (depMatch) {
|
|
21
|
+
const reason = (depMatch[1] ?? "").trim();
|
|
22
|
+
chosen = take(chosen, reason.length > 0 ? { tier: "deprecated", reason } : { tier: "deprecated" });
|
|
23
|
+
}
|
|
24
|
+
if (internalRe.test(stripped)) chosen = take(chosen, { tier: "internal" });
|
|
25
|
+
return chosen;
|
|
26
|
+
}
|
|
27
|
+
function take(current, candidate) {
|
|
28
|
+
if (!current) return candidate;
|
|
29
|
+
const cur = TIER_PRECEDENCE.get(current.tier) ?? 0;
|
|
30
|
+
const cand = TIER_PRECEDENCE.get(candidate.tier) ?? 0;
|
|
31
|
+
return cand > cur ? candidate : current;
|
|
32
|
+
}
|
|
33
|
+
function transformSource(source) {
|
|
34
|
+
if (!source.includes("defineCommand")) {
|
|
35
|
+
return { code: source, changed: false, applied: [] };
|
|
36
|
+
}
|
|
37
|
+
const applied = [];
|
|
38
|
+
const out = [];
|
|
39
|
+
let i = 0;
|
|
40
|
+
const len = source.length;
|
|
41
|
+
let internalCount = 0;
|
|
42
|
+
while (i < len) {
|
|
43
|
+
const jsdocStart = source.indexOf("/**", i);
|
|
44
|
+
if (jsdocStart < 0) {
|
|
45
|
+
out.push(source.slice(i));
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
out.push(source.slice(i, jsdocStart));
|
|
49
|
+
const jsdocEnd = source.indexOf("*/", jsdocStart + 3);
|
|
50
|
+
if (jsdocEnd < 0) {
|
|
51
|
+
out.push(source.slice(jsdocStart));
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
const jsdocBlock = source.slice(jsdocStart, jsdocEnd + 2);
|
|
55
|
+
out.push(jsdocBlock);
|
|
56
|
+
const afterDocStart = jsdocEnd + 2;
|
|
57
|
+
const lookahead = source.slice(afterDocStart, afterDocStart + 600);
|
|
58
|
+
const dcRe = /^\s*(?:(?:export\s+)?(?:const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*)?defineCommand\s*\(\s*\{/;
|
|
59
|
+
const m = dcRe.exec(lookahead);
|
|
60
|
+
if (!m) {
|
|
61
|
+
i = afterDocStart;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const tier = parseTierDirective(jsdocBlock.slice(3, -2));
|
|
65
|
+
if (!tier) {
|
|
66
|
+
i = afterDocStart;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const openBraceAbs = afterDocStart + m[0].length;
|
|
70
|
+
const restOfFile = source.slice(openBraceAbs, openBraceAbs + 4e3);
|
|
71
|
+
if (/\btier\s*:/.test(restOfFile.slice(0, indexOfMatchingBrace(restOfFile)))) {
|
|
72
|
+
i = afterDocStart;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
out.push(source.slice(afterDocStart, openBraceAbs));
|
|
76
|
+
const injected = [];
|
|
77
|
+
injected.push(` tier: ${JSON.stringify(tier.tier)},`);
|
|
78
|
+
if (tier.tier === "deprecated" && tier.reason !== void 0) {
|
|
79
|
+
injected.push(` deprecationReason: ${JSON.stringify(tier.reason)},`);
|
|
80
|
+
}
|
|
81
|
+
if (tier.tier === "internal") {
|
|
82
|
+
injected.push(` internalToken: __actureInternalToken__,`);
|
|
83
|
+
internalCount++;
|
|
84
|
+
}
|
|
85
|
+
out.push(injected.join(""));
|
|
86
|
+
applied.push(tier.reason !== void 0 ? { tier: tier.tier, reason: tier.reason } : { tier: tier.tier });
|
|
87
|
+
i = openBraceAbs;
|
|
88
|
+
}
|
|
89
|
+
let code = out.join("");
|
|
90
|
+
if (internalCount > 0) {
|
|
91
|
+
code = INTERNAL_TOKEN_DECL + code;
|
|
92
|
+
}
|
|
93
|
+
return { code, changed: applied.length > 0, applied };
|
|
94
|
+
}
|
|
95
|
+
var INTERNAL_TOKEN_DECL = "const __actureInternalToken__ = /* @__PURE__ */ Symbol('acture.internal');\n";
|
|
96
|
+
function indexOfMatchingBrace(text) {
|
|
97
|
+
let depth = 1;
|
|
98
|
+
let i = 0;
|
|
99
|
+
const len = text.length;
|
|
100
|
+
while (i < len) {
|
|
101
|
+
const ch = text[i];
|
|
102
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
103
|
+
const quote = ch;
|
|
104
|
+
i++;
|
|
105
|
+
while (i < len) {
|
|
106
|
+
if (text[i] === "\\") {
|
|
107
|
+
i += 2;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (text[i] === quote) {
|
|
111
|
+
i++;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
i++;
|
|
115
|
+
}
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (ch === "/" && text[i + 1] === "/") {
|
|
119
|
+
while (i < len && text[i] !== "\n") i++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (ch === "/" && text[i + 1] === "*") {
|
|
123
|
+
i += 2;
|
|
124
|
+
while (i < len && !(text[i] === "*" && text[i + 1] === "/")) i++;
|
|
125
|
+
i += 2;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (ch === "{") depth++;
|
|
129
|
+
else if (ch === "}") {
|
|
130
|
+
depth--;
|
|
131
|
+
if (depth === 0) return i;
|
|
132
|
+
}
|
|
133
|
+
i++;
|
|
134
|
+
}
|
|
135
|
+
return len;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
exports.parseTierDirective = parseTierDirective;
|
|
139
|
+
exports.transformSource = transformSource;
|
|
140
|
+
//# sourceMappingURL=index.cjs.map
|
|
141
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transform.ts"],"names":[],"mappings":";;;AAkCA,IAAM,eAAA,uBAAiD,GAAA,CAAI;AAAA,EACzD,CAAC,UAAU,CAAC,CAAA;AAAA,EACZ,CAAC,gBAAgB,CAAC,CAAA;AAAA,EAClB,CAAC,cAAc,CAAC,CAAA;AAAA,EAChB,CAAC,YAAY,CAAC;AAChB,CAAC,CAAA;AAMM,SAAS,mBAAmB,SAAA,EAA8C;AAC/E,EAAA,IAAI,MAAA;AAGJ,EAAA,MAAM,QAAA,GAAW,SAAA,CAAU,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAEpD,EAAA,MAAM,QAAA,GAAW,WAAA;AACjB,EAAA,MAAM,cAAA,GAAiB,iBAAA;AACvB,EAAA,MAAM,UAAA,GAAa,aAAA;AAEnB,EAAA,MAAM,YAAA,GAAe,8BAAA;AAErB,EAAA,IAAI,QAAA,CAAS,IAAA,CAAK,QAAQ,CAAA,EAAG,MAAA,GAAS,KAAK,MAAA,EAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,CAAA;AACrE,EAAA,IAAI,cAAA,CAAe,IAAA,CAAK,QAAQ,CAAA,EAAG,MAAA,GAAS,KAAK,MAAA,EAAQ,EAAE,IAAA,EAAM,cAAA,EAAgB,CAAA;AACjF,EAAA,MAAM,QAAA,GAAW,YAAA,CAAa,IAAA,CAAK,QAAQ,CAAA;AAC3C,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,MAAM,MAAA,GAAA,CAAU,QAAA,CAAS,CAAC,CAAA,IAAK,IAAI,IAAA,EAAK;AACxC,IAAA,MAAA,GAAS,IAAA,CAAK,MAAA,EAAQ,MAAA,CAAO,MAAA,GAAS,CAAA,GAAI,EAAE,IAAA,EAAM,YAAA,EAAc,MAAA,EAAO,GAAI,EAAE,IAAA,EAAM,cAAc,CAAA;AAAA,EACnG;AACA,EAAA,IAAI,UAAA,CAAW,IAAA,CAAK,QAAQ,CAAA,EAAG,MAAA,GAAS,KAAK,MAAA,EAAQ,EAAE,IAAA,EAAM,UAAA,EAAY,CAAA;AAEzE,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,IAAA,CACP,SACA,SAAA,EACe;AACf,EAAA,IAAI,CAAC,SAAS,OAAO,SAAA;AACrB,EAAA,MAAM,GAAA,GAAM,eAAA,CAAgB,GAAA,CAAI,OAAA,CAAQ,IAAI,CAAA,IAAK,CAAA;AACjD,EAAA,MAAM,IAAA,GAAO,eAAA,CAAgB,GAAA,CAAI,SAAA,CAAU,IAAI,CAAA,IAAK,CAAA;AACpD,EAAA,OAAO,IAAA,GAAO,MAAM,SAAA,GAAY,OAAA;AAClC;AAuBO,SAAS,gBAAgB,MAAA,EAAiC;AAE/D,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,eAAe,CAAA,EAAG;AACrC,IAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,SAAS,KAAA,EAAO,OAAA,EAAS,EAAC,EAAE;AAAA,EACrD;AAEA,EAAA,MAAM,UAAkD,EAAC;AAGzD,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,MAAM,MAAM,MAAA,CAAO,MAAA;AACnB,EAAA,IAAI,aAAA,GAAgB,CAAA;AAEpB,EAAA,OAAO,IAAI,GAAA,EAAK;AACd,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,OAAA,CAAQ,KAAA,EAAO,CAAC,CAAA;AAC1C,IAAA,IAAI,aAAa,CAAA,EAAG;AAClB,MAAA,GAAA,CAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAC,CAAC,CAAA;AACxB,MAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,UAAU,CAAC,CAAA;AACpC,IAAA,MAAM,QAAA,GAAW,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,aAAa,CAAC,CAAA;AACpD,IAAA,IAAI,WAAW,CAAA,EAAG;AAChB,MAAA,GAAA,CAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,UAAU,CAAC,CAAA;AACjC,MAAA;AAAA,IACF;AACA,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,CAAM,UAAA,EAAY,WAAW,CAAC,CAAA;AACxD,IAAA,GAAA,CAAI,KAAK,UAAU,CAAA;AAInB,IAAA,MAAM,gBAAgB,QAAA,GAAW,CAAA;AACjC,IAAA,MAAM,SAAA,GAAY,MAAA,CAAO,KAAA,CAAM,aAAA,EAAe,gBAAgB,GAAG,CAAA;AAMjE,IAAA,MAAM,IAAA,GAAO,2FAAA;AACb,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,SAAS,CAAA;AAC7B,IAAA,IAAI,CAAC,CAAA,EAAG;AACN,MAAA,CAAA,GAAI,aAAA;AACJ,MAAA;AAAA,IACF;AACA,IAAA,MAAM,OAAO,kBAAA,CAAmB,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA;AACvD,IAAA,IAAI,CAAC,IAAA,EAAM;AACT,MAAA,CAAA,GAAI,aAAA;AACJ,MAAA;AAAA,IACF;AAIA,IAAA,MAAM,YAAA,GAAe,aAAA,GAAgB,CAAA,CAAE,CAAC,CAAA,CAAE,MAAA;AAE1C,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,CAAM,YAAA,EAAc,eAAe,GAAI,CAAA;AACjE,IAAA,IAAI,YAAA,CAAa,KAAK,UAAA,CAAW,KAAA,CAAM,GAAG,oBAAA,CAAqB,UAAU,CAAC,CAAC,CAAA,EAAG;AAC5E,MAAA,CAAA,GAAI,aAAA;AACJ,MAAA;AAAA,IACF;AAGA,IAAA,GAAA,CAAI,IAAA,CAAK,MAAA,CAAO,KAAA,CAAM,aAAA,EAAe,YAAY,CAAC,CAAA;AAGlD,IAAA,MAAM,WAAqB,EAAC;AAC5B,IAAA,QAAA,CAAS,KAAK,CAAA,OAAA,EAAU,IAAA,CAAK,UAAU,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA,CAAG,CAAA;AACpD,IAAA,IAAI,IAAA,CAAK,IAAA,KAAS,YAAA,IAAgB,IAAA,CAAK,WAAW,MAAA,EAAW;AAC3D,MAAA,QAAA,CAAS,KAAK,CAAA,oBAAA,EAAuB,IAAA,CAAK,UAAU,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA,CAAG,CAAA;AAAA,IACrE;AACA,IAAA,IAAI,IAAA,CAAK,SAAS,UAAA,EAAY;AAC5B,MAAA,QAAA,CAAS,KAAK,CAAA,wCAAA,CAA0C,CAAA;AACxD,MAAA,aAAA,EAAA;AAAA,IACF;AACA,IAAA,GAAA,CAAI,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,EAAE,CAAC,CAAA;AAE1B,IAAA,OAAA,CAAQ,KAAK,IAAA,CAAK,MAAA,KAAW,MAAA,GAAY,EAAE,MAAM,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ,IAAA,CAAK,QAAO,GAAI,EAAE,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA;AAEvG,IAAA,CAAA,GAAI,YAAA;AAAA,EACN;AAEA,EAAA,IAAI,IAAA,GAAO,GAAA,CAAI,IAAA,CAAK,EAAE,CAAA;AACtB,EAAA,IAAI,gBAAgB,CAAA,EAAG;AACrB,IAAA,IAAA,GAAO,mBAAA,GAAsB,IAAA;AAAA,EAC/B;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,CAAQ,MAAA,GAAS,GAAG,OAAA,EAAQ;AACtD;AAIA,IAAM,mBAAA,GACJ,8EAAA;AAgBF,SAAS,qBAAqB,IAAA,EAAsB;AAClD,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,CAAA,GAAI,CAAA;AACR,EAAA,MAAM,MAAM,IAAA,CAAK,MAAA;AACjB,EAAA,OAAO,IAAI,GAAA,EAAK;AACd,IAAA,MAAM,EAAA,GAAK,KAAK,CAAC,CAAA;AACjB,IAAA,IAAI,EAAA,KAAO,GAAA,IAAO,EAAA,KAAO,GAAA,IAAO,OAAO,GAAA,EAAK;AAC1C,MAAA,MAAM,KAAA,GAAQ,EAAA;AACd,MAAA,CAAA,EAAA;AACA,MAAA,OAAO,IAAI,GAAA,EAAK;AACd,QAAA,IAAI,IAAA,CAAK,CAAC,CAAA,KAAM,IAAA,EAAM;AAAE,UAAA,CAAA,IAAK,CAAA;AAAG,UAAA;AAAA,QAAU;AAC1C,QAAA,IAAI,IAAA,CAAK,CAAC,CAAA,KAAM,KAAA,EAAO;AAAE,UAAA,CAAA,EAAA;AAAK,UAAA;AAAA,QAAO;AACrC,QAAA,CAAA,EAAA;AAAA,MACF;AACA,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,GAAA,IAAO,IAAA,CAAK,CAAA,GAAI,CAAC,MAAM,GAAA,EAAK;AAErC,MAAA,OAAO,CAAA,GAAI,GAAA,IAAO,IAAA,CAAK,CAAC,MAAM,IAAA,EAAM,CAAA,EAAA;AACpC,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,GAAA,IAAO,IAAA,CAAK,CAAA,GAAI,CAAC,MAAM,GAAA,EAAK;AACrC,MAAA,CAAA,IAAK,CAAA;AACL,MAAA,OAAO,CAAA,GAAI,GAAA,IAAO,EAAE,IAAA,CAAK,CAAC,CAAA,KAAM,GAAA,IAAO,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,KAAM,GAAA,CAAA,EAAM,CAAA,EAAA;AAC7D,MAAA,CAAA,IAAK,CAAA;AACL,MAAA;AAAA,IACF;AACA,IAAA,IAAI,OAAO,GAAA,EAAK,KAAA,EAAA;AAAA,SAAA,IACP,OAAO,GAAA,EAAK;AACnB,MAAA,KAAA,EAAA;AACA,MAAA,IAAI,KAAA,KAAU,GAAG,OAAO,CAAA;AAAA,IAC1B;AACA,IAAA,CAAA,EAAA;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT","file":"index.cjs","sourcesContent":["/**\n * Pure source-transform logic. The esbuild and Vite plugin wrappers\n * import this and call it from their respective transform hooks.\n *\n * Strategy: regex-based, intentionally conservative. We match a JSDoc\n * block immediately preceding a `defineCommand({ ... })` call, parse\n * the tier tag(s) from the JSDoc, and inject the corresponding\n * properties into the spec object literal.\n *\n * Why regex and not AST: the build step has to be fast (it runs on every\n * .ts file), and the patterns we accept are deliberately narrow — JSDoc\n * directly above the call site, no exotic syntax in between. If a user\n * writes `defineCommand` in a way our regex can't see, they fall back to\n * writing `tier: 'experimental'` explicitly in the spec — that path is\n * documented as the manual fallback.\n *\n * The four recognized tags:\n * @stable\n * @experimental\n * @internal\n * @deprecated [reason text...]\n *\n * Tag precedence: if multiple appear in the same JSDoc, we honour the\n * most-specific-restriction wins: internal > deprecated > experimental > stable.\n */\n\nexport type Tier = 'stable' | 'experimental' | 'internal' | 'deprecated';\n\nexport interface TierDirective {\n readonly tier: Tier;\n /** Non-empty only for `@deprecated <reason>`. */\n readonly reason?: string;\n}\n\nconst TIER_PRECEDENCE: ReadonlyMap<Tier, number> = new Map([\n ['stable', 0],\n ['experimental', 1],\n ['deprecated', 2],\n ['internal', 3],\n]);\n\n/**\n * Parse a JSDoc block body (the text between `/**` and `* /` ) for tier\n * tags. Returns the most-restrictive tag found, or `undefined` if none.\n */\nexport function parseTierDirective(jsdocBody: string): TierDirective | undefined {\n let chosen: TierDirective | undefined;\n // Strip the leading `*` on each line so multi-line JSDoc doesn't break\n // the tag scanner.\n const stripped = jsdocBody.replace(/^\\s*\\*\\s?/gm, '');\n\n const stableRe = /@stable\\b/;\n const experimentalRe = /@experimental\\b/;\n const internalRe = /@internal\\b/;\n // `@deprecated` may carry free-text reason on the same line.\n const deprecatedRe = /@deprecated\\b[ \\t]*([^\\n@]*)/;\n\n if (stableRe.test(stripped)) chosen = take(chosen, { tier: 'stable' });\n if (experimentalRe.test(stripped)) chosen = take(chosen, { tier: 'experimental' });\n const depMatch = deprecatedRe.exec(stripped);\n if (depMatch) {\n const reason = (depMatch[1] ?? '').trim();\n chosen = take(chosen, reason.length > 0 ? { tier: 'deprecated', reason } : { tier: 'deprecated' });\n }\n if (internalRe.test(stripped)) chosen = take(chosen, { tier: 'internal' });\n\n return chosen;\n}\n\nfunction take(\n current: TierDirective | undefined,\n candidate: TierDirective,\n): TierDirective {\n if (!current) return candidate;\n const cur = TIER_PRECEDENCE.get(current.tier) ?? 0;\n const cand = TIER_PRECEDENCE.get(candidate.tier) ?? 0;\n return cand > cur ? candidate : current;\n}\n\nexport interface TransformResult {\n readonly code: string;\n readonly changed: boolean;\n /** Tier directives applied, in order — exposed for testing. */\n readonly applied: ReadonlyArray<{ tier: Tier; reason?: string }>;\n}\n\n/**\n * Find every `/** ... * /` JSDoc block immediately followed by a\n * `defineCommand({ ... })` call, parse the tier tag(s), and inject the\n * tier (plus deprecationReason / internalToken when applicable) into\n * the spec object literal.\n *\n * - `tier` is injected at the head of the spec object.\n * - `deprecationReason` is injected after `tier`.\n * - `internalToken` references a module-scoped Symbol that is declared\n * once at the top of the file (only when at least one `@internal`\n * command is present in the file).\n *\n * Idempotent: if the spec already contains `tier:`, we leave it alone.\n */\nexport function transformSource(source: string): TransformResult {\n // Skip files that obviously do not call defineCommand.\n if (!source.includes('defineCommand')) {\n return { code: source, changed: false, applied: [] };\n }\n\n const applied: Array<{ tier: Tier; reason?: string }> = [];\n // Find every JSDoc block. We scan in order so insertion offsets remain\n // valid as we rebuild the source incrementally.\n const out: string[] = [];\n let i = 0;\n const len = source.length;\n let internalCount = 0;\n\n while (i < len) {\n const jsdocStart = source.indexOf('/**', i);\n if (jsdocStart < 0) {\n out.push(source.slice(i));\n break;\n }\n out.push(source.slice(i, jsdocStart));\n const jsdocEnd = source.indexOf('*/', jsdocStart + 3);\n if (jsdocEnd < 0) {\n out.push(source.slice(jsdocStart));\n break;\n }\n const jsdocBlock = source.slice(jsdocStart, jsdocEnd + 2);\n out.push(jsdocBlock);\n\n // Look ahead for `defineCommand(` after optional whitespace,\n // an optional `export ...`, an optional `const NAME = ` binding.\n const afterDocStart = jsdocEnd + 2;\n const lookahead = source.slice(afterDocStart, afterDocStart + 600);\n // The pattern captures the slice up to and including the opening\n // `{` of the spec object literal.\n // Optional declaration prefix (e.g. `export const NAME = `), then\n // `defineCommand({`. The declaration is optional so bare-call forms\n // are recognized too (`defineCommand({...})` on its own line).\n const dcRe = /^\\s*(?:(?:export\\s+)?(?:const|let|var)\\s+[A-Za-z_$][\\w$]*\\s*=\\s*)?defineCommand\\s*\\(\\s*\\{/;\n const m = dcRe.exec(lookahead);\n if (!m) {\n i = afterDocStart;\n continue;\n }\n const tier = parseTierDirective(jsdocBlock.slice(3, -2));\n if (!tier) {\n i = afterDocStart;\n continue;\n }\n // Compute the absolute position right after the opening `{`.\n // `m.index` is 0 (we anchored with `^`); `m[0].length` is the entire\n // match, ending at the `{` (inclusive).\n const openBraceAbs = afterDocStart + m[0].length;\n // Detect if the spec already declares `tier:` — if so, leave it.\n const restOfFile = source.slice(openBraceAbs, openBraceAbs + 4000);\n if (/\\btier\\s*:/.test(restOfFile.slice(0, indexOfMatchingBrace(restOfFile)))) {\n i = afterDocStart;\n continue;\n }\n\n // Emit everything between end-of-JSDoc and openBraceAbs.\n out.push(source.slice(afterDocStart, openBraceAbs));\n\n // Build the injected fields.\n const injected: string[] = [];\n injected.push(` tier: ${JSON.stringify(tier.tier)},`);\n if (tier.tier === 'deprecated' && tier.reason !== undefined) {\n injected.push(` deprecationReason: ${JSON.stringify(tier.reason)},`);\n }\n if (tier.tier === 'internal') {\n injected.push(` internalToken: __actureInternalToken__,`);\n internalCount++;\n }\n out.push(injected.join(''));\n\n applied.push(tier.reason !== undefined ? { tier: tier.tier, reason: tier.reason } : { tier: tier.tier });\n\n i = openBraceAbs;\n }\n\n let code = out.join('');\n if (internalCount > 0) {\n code = INTERNAL_TOKEN_DECL + code;\n }\n return { code, changed: applied.length > 0, applied };\n}\n\n/** Declared at module top so every `@internal` command in the file\n * shares it. Cross-module callers cannot see it. */\nconst INTERNAL_TOKEN_DECL =\n \"const __actureInternalToken__ = /* @__PURE__ */ Symbol('acture.internal');\\n\";\n\n/**\n * Find the offset of the matching closing brace for a string that\n * starts immediately after an opening `{` (the `{` is NOT in `text`).\n * Returns the index of the `}` (relative to `text`) on success, or\n * `text.length` if no balanced close is found.\n *\n * The scanner is intentionally minimal — it tracks nested `{}` only.\n * It treats string and template literals as opaque (skips matching\n * braces inside them) to a first approximation: handles single-quoted,\n * double-quoted, and backtick strings; does NOT handle template\n * substitutions perfectly (a `${` inside a backtick may foil it). The\n * defineCommand spec object is shallow enough that this is fine in\n * practice; users with exotic templates can write `tier: 'X'` manually.\n */\nfunction indexOfMatchingBrace(text: string): number {\n let depth = 1;\n let i = 0;\n const len = text.length;\n while (i < len) {\n const ch = text[i]!;\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n const quote = ch;\n i++;\n while (i < len) {\n if (text[i] === '\\\\') { i += 2; continue; }\n if (text[i] === quote) { i++; break; }\n i++;\n }\n continue;\n }\n if (ch === '/' && text[i + 1] === '/') {\n // line comment\n while (i < len && text[i] !== '\\n') i++;\n continue;\n }\n if (ch === '/' && text[i + 1] === '*') {\n i += 2;\n while (i < len && !(text[i] === '*' && text[i + 1] === '/')) i++;\n i += 2;\n continue;\n }\n if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) return i;\n }\n i++;\n }\n return len;\n}\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure source-transform logic. The esbuild and Vite plugin wrappers
|
|
3
|
+
* import this and call it from their respective transform hooks.
|
|
4
|
+
*
|
|
5
|
+
* Strategy: regex-based, intentionally conservative. We match a JSDoc
|
|
6
|
+
* block immediately preceding a `defineCommand({ ... })` call, parse
|
|
7
|
+
* the tier tag(s) from the JSDoc, and inject the corresponding
|
|
8
|
+
* properties into the spec object literal.
|
|
9
|
+
*
|
|
10
|
+
* Why regex and not AST: the build step has to be fast (it runs on every
|
|
11
|
+
* .ts file), and the patterns we accept are deliberately narrow — JSDoc
|
|
12
|
+
* directly above the call site, no exotic syntax in between. If a user
|
|
13
|
+
* writes `defineCommand` in a way our regex can't see, they fall back to
|
|
14
|
+
* writing `tier: 'experimental'` explicitly in the spec — that path is
|
|
15
|
+
* documented as the manual fallback.
|
|
16
|
+
*
|
|
17
|
+
* The four recognized tags:
|
|
18
|
+
* @stable
|
|
19
|
+
* @experimental
|
|
20
|
+
* @internal
|
|
21
|
+
* @deprecated [reason text...]
|
|
22
|
+
*
|
|
23
|
+
* Tag precedence: if multiple appear in the same JSDoc, we honour the
|
|
24
|
+
* most-specific-restriction wins: internal > deprecated > experimental > stable.
|
|
25
|
+
*/
|
|
26
|
+
type Tier = 'stable' | 'experimental' | 'internal' | 'deprecated';
|
|
27
|
+
interface TierDirective {
|
|
28
|
+
readonly tier: Tier;
|
|
29
|
+
/** Non-empty only for `@deprecated <reason>`. */
|
|
30
|
+
readonly reason?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse a JSDoc block body (the text between `/**` and `* /` ) for tier
|
|
34
|
+
* tags. Returns the most-restrictive tag found, or `undefined` if none.
|
|
35
|
+
*/
|
|
36
|
+
declare function parseTierDirective(jsdocBody: string): TierDirective | undefined;
|
|
37
|
+
interface TransformResult {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly changed: boolean;
|
|
40
|
+
/** Tier directives applied, in order — exposed for testing. */
|
|
41
|
+
readonly applied: ReadonlyArray<{
|
|
42
|
+
tier: Tier;
|
|
43
|
+
reason?: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Find every `/** ... * /` JSDoc block immediately followed by a
|
|
48
|
+
* `defineCommand({ ... })` call, parse the tier tag(s), and inject the
|
|
49
|
+
* tier (plus deprecationReason / internalToken when applicable) into
|
|
50
|
+
* the spec object literal.
|
|
51
|
+
*
|
|
52
|
+
* - `tier` is injected at the head of the spec object.
|
|
53
|
+
* - `deprecationReason` is injected after `tier`.
|
|
54
|
+
* - `internalToken` references a module-scoped Symbol that is declared
|
|
55
|
+
* once at the top of the file (only when at least one `@internal`
|
|
56
|
+
* command is present in the file).
|
|
57
|
+
*
|
|
58
|
+
* Idempotent: if the spec already contains `tier:`, we leave it alone.
|
|
59
|
+
*/
|
|
60
|
+
declare function transformSource(source: string): TransformResult;
|
|
61
|
+
|
|
62
|
+
export { type Tier, type TierDirective, type TransformResult, parseTierDirective, transformSource };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure source-transform logic. The esbuild and Vite plugin wrappers
|
|
3
|
+
* import this and call it from their respective transform hooks.
|
|
4
|
+
*
|
|
5
|
+
* Strategy: regex-based, intentionally conservative. We match a JSDoc
|
|
6
|
+
* block immediately preceding a `defineCommand({ ... })` call, parse
|
|
7
|
+
* the tier tag(s) from the JSDoc, and inject the corresponding
|
|
8
|
+
* properties into the spec object literal.
|
|
9
|
+
*
|
|
10
|
+
* Why regex and not AST: the build step has to be fast (it runs on every
|
|
11
|
+
* .ts file), and the patterns we accept are deliberately narrow — JSDoc
|
|
12
|
+
* directly above the call site, no exotic syntax in between. If a user
|
|
13
|
+
* writes `defineCommand` in a way our regex can't see, they fall back to
|
|
14
|
+
* writing `tier: 'experimental'` explicitly in the spec — that path is
|
|
15
|
+
* documented as the manual fallback.
|
|
16
|
+
*
|
|
17
|
+
* The four recognized tags:
|
|
18
|
+
* @stable
|
|
19
|
+
* @experimental
|
|
20
|
+
* @internal
|
|
21
|
+
* @deprecated [reason text...]
|
|
22
|
+
*
|
|
23
|
+
* Tag precedence: if multiple appear in the same JSDoc, we honour the
|
|
24
|
+
* most-specific-restriction wins: internal > deprecated > experimental > stable.
|
|
25
|
+
*/
|
|
26
|
+
type Tier = 'stable' | 'experimental' | 'internal' | 'deprecated';
|
|
27
|
+
interface TierDirective {
|
|
28
|
+
readonly tier: Tier;
|
|
29
|
+
/** Non-empty only for `@deprecated <reason>`. */
|
|
30
|
+
readonly reason?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Parse a JSDoc block body (the text between `/**` and `* /` ) for tier
|
|
34
|
+
* tags. Returns the most-restrictive tag found, or `undefined` if none.
|
|
35
|
+
*/
|
|
36
|
+
declare function parseTierDirective(jsdocBody: string): TierDirective | undefined;
|
|
37
|
+
interface TransformResult {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly changed: boolean;
|
|
40
|
+
/** Tier directives applied, in order — exposed for testing. */
|
|
41
|
+
readonly applied: ReadonlyArray<{
|
|
42
|
+
tier: Tier;
|
|
43
|
+
reason?: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Find every `/** ... * /` JSDoc block immediately followed by a
|
|
48
|
+
* `defineCommand({ ... })` call, parse the tier tag(s), and inject the
|
|
49
|
+
* tier (plus deprecationReason / internalToken when applicable) into
|
|
50
|
+
* the spec object literal.
|
|
51
|
+
*
|
|
52
|
+
* - `tier` is injected at the head of the spec object.
|
|
53
|
+
* - `deprecationReason` is injected after `tier`.
|
|
54
|
+
* - `internalToken` references a module-scoped Symbol that is declared
|
|
55
|
+
* once at the top of the file (only when at least one `@internal`
|
|
56
|
+
* command is present in the file).
|
|
57
|
+
*
|
|
58
|
+
* Idempotent: if the spec already contains `tier:`, we leave it alone.
|
|
59
|
+
*/
|
|
60
|
+
declare function transformSource(source: string): TransformResult;
|
|
61
|
+
|
|
62
|
+
export { type Tier, type TierDirective, type TransformResult, parseTierDirective, transformSource };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
package/dist/vite.cjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/transform.ts
|
|
4
|
+
var TIER_PRECEDENCE = /* @__PURE__ */ new Map([
|
|
5
|
+
["stable", 0],
|
|
6
|
+
["experimental", 1],
|
|
7
|
+
["deprecated", 2],
|
|
8
|
+
["internal", 3]
|
|
9
|
+
]);
|
|
10
|
+
function parseTierDirective(jsdocBody) {
|
|
11
|
+
let chosen;
|
|
12
|
+
const stripped = jsdocBody.replace(/^\s*\*\s?/gm, "");
|
|
13
|
+
const stableRe = /@stable\b/;
|
|
14
|
+
const experimentalRe = /@experimental\b/;
|
|
15
|
+
const internalRe = /@internal\b/;
|
|
16
|
+
const deprecatedRe = /@deprecated\b[ \t]*([^\n@]*)/;
|
|
17
|
+
if (stableRe.test(stripped)) chosen = take(chosen, { tier: "stable" });
|
|
18
|
+
if (experimentalRe.test(stripped)) chosen = take(chosen, { tier: "experimental" });
|
|
19
|
+
const depMatch = deprecatedRe.exec(stripped);
|
|
20
|
+
if (depMatch) {
|
|
21
|
+
const reason = (depMatch[1] ?? "").trim();
|
|
22
|
+
chosen = take(chosen, reason.length > 0 ? { tier: "deprecated", reason } : { tier: "deprecated" });
|
|
23
|
+
}
|
|
24
|
+
if (internalRe.test(stripped)) chosen = take(chosen, { tier: "internal" });
|
|
25
|
+
return chosen;
|
|
26
|
+
}
|
|
27
|
+
function take(current, candidate) {
|
|
28
|
+
if (!current) return candidate;
|
|
29
|
+
const cur = TIER_PRECEDENCE.get(current.tier) ?? 0;
|
|
30
|
+
const cand = TIER_PRECEDENCE.get(candidate.tier) ?? 0;
|
|
31
|
+
return cand > cur ? candidate : current;
|
|
32
|
+
}
|
|
33
|
+
function transformSource(source) {
|
|
34
|
+
if (!source.includes("defineCommand")) {
|
|
35
|
+
return { code: source, changed: false, applied: [] };
|
|
36
|
+
}
|
|
37
|
+
const applied = [];
|
|
38
|
+
const out = [];
|
|
39
|
+
let i = 0;
|
|
40
|
+
const len = source.length;
|
|
41
|
+
let internalCount = 0;
|
|
42
|
+
while (i < len) {
|
|
43
|
+
const jsdocStart = source.indexOf("/**", i);
|
|
44
|
+
if (jsdocStart < 0) {
|
|
45
|
+
out.push(source.slice(i));
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
out.push(source.slice(i, jsdocStart));
|
|
49
|
+
const jsdocEnd = source.indexOf("*/", jsdocStart + 3);
|
|
50
|
+
if (jsdocEnd < 0) {
|
|
51
|
+
out.push(source.slice(jsdocStart));
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
const jsdocBlock = source.slice(jsdocStart, jsdocEnd + 2);
|
|
55
|
+
out.push(jsdocBlock);
|
|
56
|
+
const afterDocStart = jsdocEnd + 2;
|
|
57
|
+
const lookahead = source.slice(afterDocStart, afterDocStart + 600);
|
|
58
|
+
const dcRe = /^\s*(?:(?:export\s+)?(?:const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*)?defineCommand\s*\(\s*\{/;
|
|
59
|
+
const m = dcRe.exec(lookahead);
|
|
60
|
+
if (!m) {
|
|
61
|
+
i = afterDocStart;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const tier = parseTierDirective(jsdocBlock.slice(3, -2));
|
|
65
|
+
if (!tier) {
|
|
66
|
+
i = afterDocStart;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const openBraceAbs = afterDocStart + m[0].length;
|
|
70
|
+
const restOfFile = source.slice(openBraceAbs, openBraceAbs + 4e3);
|
|
71
|
+
if (/\btier\s*:/.test(restOfFile.slice(0, indexOfMatchingBrace(restOfFile)))) {
|
|
72
|
+
i = afterDocStart;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
out.push(source.slice(afterDocStart, openBraceAbs));
|
|
76
|
+
const injected = [];
|
|
77
|
+
injected.push(` tier: ${JSON.stringify(tier.tier)},`);
|
|
78
|
+
if (tier.tier === "deprecated" && tier.reason !== void 0) {
|
|
79
|
+
injected.push(` deprecationReason: ${JSON.stringify(tier.reason)},`);
|
|
80
|
+
}
|
|
81
|
+
if (tier.tier === "internal") {
|
|
82
|
+
injected.push(` internalToken: __actureInternalToken__,`);
|
|
83
|
+
internalCount++;
|
|
84
|
+
}
|
|
85
|
+
out.push(injected.join(""));
|
|
86
|
+
applied.push(tier.reason !== void 0 ? { tier: tier.tier, reason: tier.reason } : { tier: tier.tier });
|
|
87
|
+
i = openBraceAbs;
|
|
88
|
+
}
|
|
89
|
+
let code = out.join("");
|
|
90
|
+
if (internalCount > 0) {
|
|
91
|
+
code = INTERNAL_TOKEN_DECL + code;
|
|
92
|
+
}
|
|
93
|
+
return { code, changed: applied.length > 0, applied };
|
|
94
|
+
}
|
|
95
|
+
var INTERNAL_TOKEN_DECL = "const __actureInternalToken__ = /* @__PURE__ */ Symbol('acture.internal');\n";
|
|
96
|
+
function indexOfMatchingBrace(text) {
|
|
97
|
+
let depth = 1;
|
|
98
|
+
let i = 0;
|
|
99
|
+
const len = text.length;
|
|
100
|
+
while (i < len) {
|
|
101
|
+
const ch = text[i];
|
|
102
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
103
|
+
const quote = ch;
|
|
104
|
+
i++;
|
|
105
|
+
while (i < len) {
|
|
106
|
+
if (text[i] === "\\") {
|
|
107
|
+
i += 2;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (text[i] === quote) {
|
|
111
|
+
i++;
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
i++;
|
|
115
|
+
}
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (ch === "/" && text[i + 1] === "/") {
|
|
119
|
+
while (i < len && text[i] !== "\n") i++;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (ch === "/" && text[i + 1] === "*") {
|
|
123
|
+
i += 2;
|
|
124
|
+
while (i < len && !(text[i] === "*" && text[i + 1] === "/")) i++;
|
|
125
|
+
i += 2;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (ch === "{") depth++;
|
|
129
|
+
else if (ch === "}") {
|
|
130
|
+
depth--;
|
|
131
|
+
if (depth === 0) return i;
|
|
132
|
+
}
|
|
133
|
+
i++;
|
|
134
|
+
}
|
|
135
|
+
return len;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// src/vite.ts
|
|
139
|
+
function actureBuildTierVite(options = {}) {
|
|
140
|
+
const filter = options.filter ?? /\.tsx?$/;
|
|
141
|
+
const exclude = options.exclude ?? /node_modules/;
|
|
142
|
+
return {
|
|
143
|
+
name: "acture-build-tier",
|
|
144
|
+
enforce: "pre",
|
|
145
|
+
transform(code, id) {
|
|
146
|
+
if (!filter.test(id)) return void 0;
|
|
147
|
+
if (exclude.test(id)) return void 0;
|
|
148
|
+
const result = transformSource(code);
|
|
149
|
+
if (!result.changed) return void 0;
|
|
150
|
+
return { code: result.code, map: null };
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
exports.actureBuildTierVite = actureBuildTierVite;
|
|
156
|
+
//# sourceMappingURL=vite.cjs.map
|
|
157
|
+
//# sourceMappingURL=vite.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/transform.ts","../src/vite.ts"],"names":[],"mappings":"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","file":"vite.cjs","sourcesContent":["/**\n * Pure source-transform logic. The esbuild and Vite plugin wrappers\n * import this and call it from their respective transform hooks.\n *\n * Strategy: regex-based, intentionally conservative. We match a JSDoc\n * block immediately preceding a `defineCommand({ ... })` call, parse\n * the tier tag(s) from the JSDoc, and inject the corresponding\n * properties into the spec object literal.\n *\n * Why regex and not AST: the build step has to be fast (it runs on every\n * .ts file), and the patterns we accept are deliberately narrow — JSDoc\n * directly above the call site, no exotic syntax in between. If a user\n * writes `defineCommand` in a way our regex can't see, they fall back to\n * writing `tier: 'experimental'` explicitly in the spec — that path is\n * documented as the manual fallback.\n *\n * The four recognized tags:\n * @stable\n * @experimental\n * @internal\n * @deprecated [reason text...]\n *\n * Tag precedence: if multiple appear in the same JSDoc, we honour the\n * most-specific-restriction wins: internal > deprecated > experimental > stable.\n */\n\nexport type Tier = 'stable' | 'experimental' | 'internal' | 'deprecated';\n\nexport interface TierDirective {\n readonly tier: Tier;\n /** Non-empty only for `@deprecated <reason>`. */\n readonly reason?: string;\n}\n\nconst TIER_PRECEDENCE: ReadonlyMap<Tier, number> = new Map([\n ['stable', 0],\n ['experimental', 1],\n ['deprecated', 2],\n ['internal', 3],\n]);\n\n/**\n * Parse a JSDoc block body (the text between `/**` and `* /` ) for tier\n * tags. Returns the most-restrictive tag found, or `undefined` if none.\n */\nexport function parseTierDirective(jsdocBody: string): TierDirective | undefined {\n let chosen: TierDirective | undefined;\n // Strip the leading `*` on each line so multi-line JSDoc doesn't break\n // the tag scanner.\n const stripped = jsdocBody.replace(/^\\s*\\*\\s?/gm, '');\n\n const stableRe = /@stable\\b/;\n const experimentalRe = /@experimental\\b/;\n const internalRe = /@internal\\b/;\n // `@deprecated` may carry free-text reason on the same line.\n const deprecatedRe = /@deprecated\\b[ \\t]*([^\\n@]*)/;\n\n if (stableRe.test(stripped)) chosen = take(chosen, { tier: 'stable' });\n if (experimentalRe.test(stripped)) chosen = take(chosen, { tier: 'experimental' });\n const depMatch = deprecatedRe.exec(stripped);\n if (depMatch) {\n const reason = (depMatch[1] ?? '').trim();\n chosen = take(chosen, reason.length > 0 ? { tier: 'deprecated', reason } : { tier: 'deprecated' });\n }\n if (internalRe.test(stripped)) chosen = take(chosen, { tier: 'internal' });\n\n return chosen;\n}\n\nfunction take(\n current: TierDirective | undefined,\n candidate: TierDirective,\n): TierDirective {\n if (!current) return candidate;\n const cur = TIER_PRECEDENCE.get(current.tier) ?? 0;\n const cand = TIER_PRECEDENCE.get(candidate.tier) ?? 0;\n return cand > cur ? candidate : current;\n}\n\nexport interface TransformResult {\n readonly code: string;\n readonly changed: boolean;\n /** Tier directives applied, in order — exposed for testing. */\n readonly applied: ReadonlyArray<{ tier: Tier; reason?: string }>;\n}\n\n/**\n * Find every `/** ... * /` JSDoc block immediately followed by a\n * `defineCommand({ ... })` call, parse the tier tag(s), and inject the\n * tier (plus deprecationReason / internalToken when applicable) into\n * the spec object literal.\n *\n * - `tier` is injected at the head of the spec object.\n * - `deprecationReason` is injected after `tier`.\n * - `internalToken` references a module-scoped Symbol that is declared\n * once at the top of the file (only when at least one `@internal`\n * command is present in the file).\n *\n * Idempotent: if the spec already contains `tier:`, we leave it alone.\n */\nexport function transformSource(source: string): TransformResult {\n // Skip files that obviously do not call defineCommand.\n if (!source.includes('defineCommand')) {\n return { code: source, changed: false, applied: [] };\n }\n\n const applied: Array<{ tier: Tier; reason?: string }> = [];\n // Find every JSDoc block. We scan in order so insertion offsets remain\n // valid as we rebuild the source incrementally.\n const out: string[] = [];\n let i = 0;\n const len = source.length;\n let internalCount = 0;\n\n while (i < len) {\n const jsdocStart = source.indexOf('/**', i);\n if (jsdocStart < 0) {\n out.push(source.slice(i));\n break;\n }\n out.push(source.slice(i, jsdocStart));\n const jsdocEnd = source.indexOf('*/', jsdocStart + 3);\n if (jsdocEnd < 0) {\n out.push(source.slice(jsdocStart));\n break;\n }\n const jsdocBlock = source.slice(jsdocStart, jsdocEnd + 2);\n out.push(jsdocBlock);\n\n // Look ahead for `defineCommand(` after optional whitespace,\n // an optional `export ...`, an optional `const NAME = ` binding.\n const afterDocStart = jsdocEnd + 2;\n const lookahead = source.slice(afterDocStart, afterDocStart + 600);\n // The pattern captures the slice up to and including the opening\n // `{` of the spec object literal.\n // Optional declaration prefix (e.g. `export const NAME = `), then\n // `defineCommand({`. The declaration is optional so bare-call forms\n // are recognized too (`defineCommand({...})` on its own line).\n const dcRe = /^\\s*(?:(?:export\\s+)?(?:const|let|var)\\s+[A-Za-z_$][\\w$]*\\s*=\\s*)?defineCommand\\s*\\(\\s*\\{/;\n const m = dcRe.exec(lookahead);\n if (!m) {\n i = afterDocStart;\n continue;\n }\n const tier = parseTierDirective(jsdocBlock.slice(3, -2));\n if (!tier) {\n i = afterDocStart;\n continue;\n }\n // Compute the absolute position right after the opening `{`.\n // `m.index` is 0 (we anchored with `^`); `m[0].length` is the entire\n // match, ending at the `{` (inclusive).\n const openBraceAbs = afterDocStart + m[0].length;\n // Detect if the spec already declares `tier:` — if so, leave it.\n const restOfFile = source.slice(openBraceAbs, openBraceAbs + 4000);\n if (/\\btier\\s*:/.test(restOfFile.slice(0, indexOfMatchingBrace(restOfFile)))) {\n i = afterDocStart;\n continue;\n }\n\n // Emit everything between end-of-JSDoc and openBraceAbs.\n out.push(source.slice(afterDocStart, openBraceAbs));\n\n // Build the injected fields.\n const injected: string[] = [];\n injected.push(` tier: ${JSON.stringify(tier.tier)},`);\n if (tier.tier === 'deprecated' && tier.reason !== undefined) {\n injected.push(` deprecationReason: ${JSON.stringify(tier.reason)},`);\n }\n if (tier.tier === 'internal') {\n injected.push(` internalToken: __actureInternalToken__,`);\n internalCount++;\n }\n out.push(injected.join(''));\n\n applied.push(tier.reason !== undefined ? { tier: tier.tier, reason: tier.reason } : { tier: tier.tier });\n\n i = openBraceAbs;\n }\n\n let code = out.join('');\n if (internalCount > 0) {\n code = INTERNAL_TOKEN_DECL + code;\n }\n return { code, changed: applied.length > 0, applied };\n}\n\n/** Declared at module top so every `@internal` command in the file\n * shares it. Cross-module callers cannot see it. */\nconst INTERNAL_TOKEN_DECL =\n \"const __actureInternalToken__ = /* @__PURE__ */ Symbol('acture.internal');\\n\";\n\n/**\n * Find the offset of the matching closing brace for a string that\n * starts immediately after an opening `{` (the `{` is NOT in `text`).\n * Returns the index of the `}` (relative to `text`) on success, or\n * `text.length` if no balanced close is found.\n *\n * The scanner is intentionally minimal — it tracks nested `{}` only.\n * It treats string and template literals as opaque (skips matching\n * braces inside them) to a first approximation: handles single-quoted,\n * double-quoted, and backtick strings; does NOT handle template\n * substitutions perfectly (a `${` inside a backtick may foil it). The\n * defineCommand spec object is shallow enough that this is fine in\n * practice; users with exotic templates can write `tier: 'X'` manually.\n */\nfunction indexOfMatchingBrace(text: string): number {\n let depth = 1;\n let i = 0;\n const len = text.length;\n while (i < len) {\n const ch = text[i]!;\n if (ch === '\"' || ch === \"'\" || ch === '`') {\n const quote = ch;\n i++;\n while (i < len) {\n if (text[i] === '\\\\') { i += 2; continue; }\n if (text[i] === quote) { i++; break; }\n i++;\n }\n continue;\n }\n if (ch === '/' && text[i + 1] === '/') {\n // line comment\n while (i < len && text[i] !== '\\n') i++;\n continue;\n }\n if (ch === '/' && text[i + 1] === '*') {\n i += 2;\n while (i < len && !(text[i] === '*' && text[i + 1] === '/')) i++;\n i += 2;\n continue;\n }\n if (ch === '{') depth++;\n else if (ch === '}') {\n depth--;\n if (depth === 0) return i;\n }\n i++;\n }\n return len;\n}\n","/**\n * Vite plugin. Mirrors the esbuild plugin for `vite` consumers (the\n * greenfield example uses Vite).\n *\n * Usage in vite.config.ts:\n *\n * import { actureBuildTierVite } from 'acture-build-tier/vite';\n * export default defineConfig({\n * plugins: [actureBuildTierVite()],\n * });\n *\n * Vite runs `transform` hooks for every loaded module; we filter to\n * `.ts` / `.tsx` under the consumer's source tree and skip\n * `node_modules`.\n */\n\nimport { transformSource } from './transform.js';\n\n/** Minimal Vite plugin shape. Avoids pulling in vite as a dep. */\nexport interface VitePlugin {\n name: string;\n enforce?: 'pre' | 'post';\n transform?(code: string, id: string): { code: string; map: null } | undefined;\n}\n\nexport interface ActureBuildTierViteOptions {\n /** File-path regex. Defaults to `/\\\\.tsx?$/`. */\n filter?: RegExp;\n /** Skip transform for paths matching this regex. Defaults to a\n * `node_modules` matcher. */\n exclude?: RegExp;\n}\n\n/** Vite plugin wrapper. Marked `enforce: 'pre'` so the transform runs\n * before Vite's own TypeScript transform — the JSDoc must still be in\n * the source when we scan. */\nexport function actureBuildTierVite(\n options: ActureBuildTierViteOptions = {},\n): VitePlugin {\n const filter = options.filter ?? /\\.tsx?$/;\n const exclude = options.exclude ?? /node_modules/;\n return {\n name: 'acture-build-tier',\n enforce: 'pre',\n transform(code, id) {\n if (!filter.test(id)) return undefined;\n if (exclude.test(id)) return undefined;\n const result = transformSource(code);\n if (!result.changed) return undefined;\n return { code: result.code, map: null };\n },\n };\n}\n"]}
|
package/dist/vite.d.cts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin. Mirrors the esbuild plugin for `vite` consumers (the
|
|
3
|
+
* greenfield example uses Vite).
|
|
4
|
+
*
|
|
5
|
+
* Usage in vite.config.ts:
|
|
6
|
+
*
|
|
7
|
+
* import { actureBuildTierVite } from 'acture-build-tier/vite';
|
|
8
|
+
* export default defineConfig({
|
|
9
|
+
* plugins: [actureBuildTierVite()],
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* Vite runs `transform` hooks for every loaded module; we filter to
|
|
13
|
+
* `.ts` / `.tsx` under the consumer's source tree and skip
|
|
14
|
+
* `node_modules`.
|
|
15
|
+
*/
|
|
16
|
+
/** Minimal Vite plugin shape. Avoids pulling in vite as a dep. */
|
|
17
|
+
interface VitePlugin {
|
|
18
|
+
name: string;
|
|
19
|
+
enforce?: 'pre' | 'post';
|
|
20
|
+
transform?(code: string, id: string): {
|
|
21
|
+
code: string;
|
|
22
|
+
map: null;
|
|
23
|
+
} | undefined;
|
|
24
|
+
}
|
|
25
|
+
interface ActureBuildTierViteOptions {
|
|
26
|
+
/** File-path regex. Defaults to `/\\.tsx?$/`. */
|
|
27
|
+
filter?: RegExp;
|
|
28
|
+
/** Skip transform for paths matching this regex. Defaults to a
|
|
29
|
+
* `node_modules` matcher. */
|
|
30
|
+
exclude?: RegExp;
|
|
31
|
+
}
|
|
32
|
+
/** Vite plugin wrapper. Marked `enforce: 'pre'` so the transform runs
|
|
33
|
+
* before Vite's own TypeScript transform — the JSDoc must still be in
|
|
34
|
+
* the source when we scan. */
|
|
35
|
+
declare function actureBuildTierVite(options?: ActureBuildTierViteOptions): VitePlugin;
|
|
36
|
+
|
|
37
|
+
export { type ActureBuildTierViteOptions, type VitePlugin, actureBuildTierVite };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin. Mirrors the esbuild plugin for `vite` consumers (the
|
|
3
|
+
* greenfield example uses Vite).
|
|
4
|
+
*
|
|
5
|
+
* Usage in vite.config.ts:
|
|
6
|
+
*
|
|
7
|
+
* import { actureBuildTierVite } from 'acture-build-tier/vite';
|
|
8
|
+
* export default defineConfig({
|
|
9
|
+
* plugins: [actureBuildTierVite()],
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* Vite runs `transform` hooks for every loaded module; we filter to
|
|
13
|
+
* `.ts` / `.tsx` under the consumer's source tree and skip
|
|
14
|
+
* `node_modules`.
|
|
15
|
+
*/
|
|
16
|
+
/** Minimal Vite plugin shape. Avoids pulling in vite as a dep. */
|
|
17
|
+
interface VitePlugin {
|
|
18
|
+
name: string;
|
|
19
|
+
enforce?: 'pre' | 'post';
|
|
20
|
+
transform?(code: string, id: string): {
|
|
21
|
+
code: string;
|
|
22
|
+
map: null;
|
|
23
|
+
} | undefined;
|
|
24
|
+
}
|
|
25
|
+
interface ActureBuildTierViteOptions {
|
|
26
|
+
/** File-path regex. Defaults to `/\\.tsx?$/`. */
|
|
27
|
+
filter?: RegExp;
|
|
28
|
+
/** Skip transform for paths matching this regex. Defaults to a
|
|
29
|
+
* `node_modules` matcher. */
|
|
30
|
+
exclude?: RegExp;
|
|
31
|
+
}
|
|
32
|
+
/** Vite plugin wrapper. Marked `enforce: 'pre'` so the transform runs
|
|
33
|
+
* before Vite's own TypeScript transform — the JSDoc must still be in
|
|
34
|
+
* the source when we scan. */
|
|
35
|
+
declare function actureBuildTierVite(options?: ActureBuildTierViteOptions): VitePlugin;
|
|
36
|
+
|
|
37
|
+
export { type ActureBuildTierViteOptions, type VitePlugin, actureBuildTierVite };
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { transformSource } from './chunk-SWJN6WEL.js';
|
|
2
|
+
|
|
3
|
+
// src/vite.ts
|
|
4
|
+
function actureBuildTierVite(options = {}) {
|
|
5
|
+
const filter = options.filter ?? /\.tsx?$/;
|
|
6
|
+
const exclude = options.exclude ?? /node_modules/;
|
|
7
|
+
return {
|
|
8
|
+
name: "acture-build-tier",
|
|
9
|
+
enforce: "pre",
|
|
10
|
+
transform(code, id) {
|
|
11
|
+
if (!filter.test(id)) return void 0;
|
|
12
|
+
if (exclude.test(id)) return void 0;
|
|
13
|
+
const result = transformSource(code);
|
|
14
|
+
if (!result.changed) return void 0;
|
|
15
|
+
return { code: result.code, map: null };
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { actureBuildTierVite };
|
|
21
|
+
//# sourceMappingURL=vite.js.map
|
|
22
|
+
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/vite.ts"],"names":[],"mappings":";;;AAoCO,SAAS,mBAAA,CACd,OAAA,GAAsC,EAAC,EAC3B;AACZ,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAA,IAAU,SAAA;AACjC,EAAA,MAAM,OAAA,GAAU,QAAQ,OAAA,IAAW,cAAA;AACnC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,mBAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IACT,SAAA,CAAU,MAAM,EAAA,EAAI;AAClB,MAAA,IAAI,CAAC,MAAA,CAAO,IAAA,CAAK,EAAE,GAAG,OAAO,MAAA;AAC7B,MAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,EAAE,CAAA,EAAG,OAAO,MAAA;AAC7B,MAAA,MAAM,MAAA,GAAS,gBAAgB,IAAI,CAAA;AACnC,MAAA,IAAI,CAAC,MAAA,CAAO,OAAA,EAAS,OAAO,MAAA;AAC5B,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,CAAO,IAAA,EAAM,KAAK,IAAA,EAAK;AAAA,IACxC;AAAA,GACF;AACF","file":"vite.js","sourcesContent":["/**\n * Vite plugin. Mirrors the esbuild plugin for `vite` consumers (the\n * greenfield example uses Vite).\n *\n * Usage in vite.config.ts:\n *\n * import { actureBuildTierVite } from 'acture-build-tier/vite';\n * export default defineConfig({\n * plugins: [actureBuildTierVite()],\n * });\n *\n * Vite runs `transform` hooks for every loaded module; we filter to\n * `.ts` / `.tsx` under the consumer's source tree and skip\n * `node_modules`.\n */\n\nimport { transformSource } from './transform.js';\n\n/** Minimal Vite plugin shape. Avoids pulling in vite as a dep. */\nexport interface VitePlugin {\n name: string;\n enforce?: 'pre' | 'post';\n transform?(code: string, id: string): { code: string; map: null } | undefined;\n}\n\nexport interface ActureBuildTierViteOptions {\n /** File-path regex. Defaults to `/\\\\.tsx?$/`. */\n filter?: RegExp;\n /** Skip transform for paths matching this regex. Defaults to a\n * `node_modules` matcher. */\n exclude?: RegExp;\n}\n\n/** Vite plugin wrapper. Marked `enforce: 'pre'` so the transform runs\n * before Vite's own TypeScript transform — the JSDoc must still be in\n * the source when we scan. */\nexport function actureBuildTierVite(\n options: ActureBuildTierViteOptions = {},\n): VitePlugin {\n const filter = options.filter ?? /\\.tsx?$/;\n const exclude = options.exclude ?? /node_modules/;\n return {\n name: 'acture-build-tier',\n enforce: 'pre',\n transform(code, id) {\n if (!filter.test(id)) return undefined;\n if (exclude.test(id)) return undefined;\n const result = transformSource(code);\n if (!result.changed) return undefined;\n return { code: result.code, map: null };\n },\n };\n}\n"]}
|