@collie-lang/cli 1.3.3 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +223 -32
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var import_node_child_process2 = require("child_process");
|
|
|
28
28
|
var import_promises8 = __toESM(require("fs/promises"));
|
|
29
29
|
var import_node_fs3 = require("fs");
|
|
30
30
|
var import_node_path8 = __toESM(require("path"));
|
|
31
|
-
var
|
|
31
|
+
var import_typescript2 = __toESM(require("typescript"));
|
|
32
32
|
var import_fast_glob4 = __toESM(require("fast-glob"));
|
|
33
33
|
var import_diff = require("diff");
|
|
34
34
|
var import_picocolors7 = __toESM(require("picocolors"));
|
|
@@ -784,11 +784,13 @@ function printSuccessMessage(config) {
|
|
|
784
784
|
// src/converter.ts
|
|
785
785
|
var import_promises6 = __toESM(require("fs/promises"));
|
|
786
786
|
var import_node_path6 = __toESM(require("path"));
|
|
787
|
+
var import_typescript = __toESM(require("typescript"));
|
|
787
788
|
var import_compiler5 = require("@collie-lang/compiler");
|
|
788
789
|
async function convertFile(filepath, options = {}) {
|
|
789
790
|
const source = await import_promises6.default.readFile(filepath, "utf8");
|
|
790
791
|
const result = (0, import_compiler5.convertTsxToCollie)(source, { filename: filepath });
|
|
791
|
-
const
|
|
792
|
+
const collie = normalizeConvertedCollie(result.collie, source, filepath);
|
|
793
|
+
const { warnings } = result;
|
|
792
794
|
let outputPath;
|
|
793
795
|
if (options.write) {
|
|
794
796
|
outputPath = resolveOutputPath2(filepath);
|
|
@@ -806,6 +808,195 @@ async function convertFile(filepath, options = {}) {
|
|
|
806
808
|
}
|
|
807
809
|
return { collie, warnings, outputPath };
|
|
808
810
|
}
|
|
811
|
+
function normalizeConvertedCollie(collie, source, filename) {
|
|
812
|
+
const { localParamNames, componentParamNames } = collectLocalFunctionParams(source, filename);
|
|
813
|
+
const lines = collie.replace(/\r\n?/g, "\n").split("\n");
|
|
814
|
+
const normalized = [];
|
|
815
|
+
let inInputs = false;
|
|
816
|
+
let inputsIndent = 0;
|
|
817
|
+
let inputsHeader = "";
|
|
818
|
+
let inputLines = [];
|
|
819
|
+
let seenInputs = /* @__PURE__ */ new Set();
|
|
820
|
+
const flushInputsBlock = () => {
|
|
821
|
+
if (!inInputs) {
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (inputLines.length > 0) {
|
|
825
|
+
normalized.push(inputsHeader, ...inputLines);
|
|
826
|
+
}
|
|
827
|
+
inInputs = false;
|
|
828
|
+
inputsHeader = "";
|
|
829
|
+
inputLines = [];
|
|
830
|
+
seenInputs = /* @__PURE__ */ new Set();
|
|
831
|
+
};
|
|
832
|
+
let i = 0;
|
|
833
|
+
while (i < lines.length) {
|
|
834
|
+
const rawLine = lines[i];
|
|
835
|
+
const indentMatch = rawLine.match(/^\s*/);
|
|
836
|
+
const indent = indentMatch ? indentMatch[0].length : 0;
|
|
837
|
+
const trimmed = rawLine.trimEnd();
|
|
838
|
+
if (!inInputs) {
|
|
839
|
+
if (trimmed === "#inputs") {
|
|
840
|
+
inInputs = true;
|
|
841
|
+
inputsIndent = indent;
|
|
842
|
+
inputsHeader = rawLine;
|
|
843
|
+
inputLines = [];
|
|
844
|
+
seenInputs = /* @__PURE__ */ new Set();
|
|
845
|
+
i++;
|
|
846
|
+
continue;
|
|
847
|
+
}
|
|
848
|
+
normalized.push(rawLine);
|
|
849
|
+
i++;
|
|
850
|
+
continue;
|
|
851
|
+
}
|
|
852
|
+
if (trimmed !== "" && indent <= inputsIndent) {
|
|
853
|
+
flushInputsBlock();
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
if (trimmed === "") {
|
|
857
|
+
i++;
|
|
858
|
+
continue;
|
|
859
|
+
}
|
|
860
|
+
const content = trimmed.trim();
|
|
861
|
+
const nameMatch = content.match(/^([A-Za-z_$][A-Za-z0-9_$]*)/);
|
|
862
|
+
if (!nameMatch) {
|
|
863
|
+
i++;
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
const name = nameMatch[1];
|
|
867
|
+
if (localParamNames.has(name) && !componentParamNames.has(name)) {
|
|
868
|
+
i++;
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
if (!seenInputs.has(name)) {
|
|
872
|
+
const lineIndent = rawLine.slice(0, indent);
|
|
873
|
+
inputLines.push(`${lineIndent}${name}`);
|
|
874
|
+
seenInputs.add(name);
|
|
875
|
+
}
|
|
876
|
+
i++;
|
|
877
|
+
}
|
|
878
|
+
flushInputsBlock();
|
|
879
|
+
return normalized.join("\n");
|
|
880
|
+
}
|
|
881
|
+
function collectLocalFunctionParams(source, filename) {
|
|
882
|
+
const sourceFile = import_typescript.default.createSourceFile(
|
|
883
|
+
filename,
|
|
884
|
+
source,
|
|
885
|
+
import_typescript.default.ScriptTarget.Latest,
|
|
886
|
+
true,
|
|
887
|
+
inferScriptKind(filename)
|
|
888
|
+
);
|
|
889
|
+
const componentNode = findComponentFunction(sourceFile);
|
|
890
|
+
const componentParamNames = /* @__PURE__ */ new Set();
|
|
891
|
+
if (componentNode) {
|
|
892
|
+
collectParamNames(componentNode.parameters, componentParamNames, sourceFile);
|
|
893
|
+
}
|
|
894
|
+
const localParamNames = /* @__PURE__ */ new Set();
|
|
895
|
+
const visit = (node) => {
|
|
896
|
+
if (isFunctionNode(node) && node !== componentNode) {
|
|
897
|
+
collectParamNames(node.parameters, localParamNames, sourceFile);
|
|
898
|
+
}
|
|
899
|
+
import_typescript.default.forEachChild(node, visit);
|
|
900
|
+
};
|
|
901
|
+
visit(sourceFile);
|
|
902
|
+
return { localParamNames, componentParamNames };
|
|
903
|
+
}
|
|
904
|
+
function isFunctionNode(node) {
|
|
905
|
+
return import_typescript.default.isFunctionDeclaration(node) || import_typescript.default.isFunctionExpression(node) || import_typescript.default.isArrowFunction(node) || import_typescript.default.isMethodDeclaration(node);
|
|
906
|
+
}
|
|
907
|
+
function collectParamNames(params, names, sourceFile) {
|
|
908
|
+
for (const param of params) {
|
|
909
|
+
collectBindingNames(param.name, names, sourceFile);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
function collectBindingNames(name, names, sourceFile) {
|
|
913
|
+
if (import_typescript.default.isIdentifier(name)) {
|
|
914
|
+
names.add(name.text);
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
if (import_typescript.default.isObjectBindingPattern(name)) {
|
|
918
|
+
for (const element of name.elements) {
|
|
919
|
+
if (element.propertyName) {
|
|
920
|
+
const propName = getPropertyNameText(element.propertyName, sourceFile);
|
|
921
|
+
if (propName) {
|
|
922
|
+
names.add(propName);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
collectBindingNames(element.name, names, sourceFile);
|
|
926
|
+
}
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
if (import_typescript.default.isArrayBindingPattern(name)) {
|
|
930
|
+
for (const element of name.elements) {
|
|
931
|
+
if (import_typescript.default.isBindingElement(element)) {
|
|
932
|
+
collectBindingNames(element.name, names, sourceFile);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
function getPropertyNameText(name, sourceFile) {
|
|
938
|
+
if (import_typescript.default.isIdentifier(name) || import_typescript.default.isStringLiteral(name) || import_typescript.default.isNumericLiteral(name)) {
|
|
939
|
+
return name.text;
|
|
940
|
+
}
|
|
941
|
+
const raw = name.getText(sourceFile);
|
|
942
|
+
return raw ? raw : null;
|
|
943
|
+
}
|
|
944
|
+
function findComponentFunction(sourceFile) {
|
|
945
|
+
for (const statement of sourceFile.statements) {
|
|
946
|
+
if (import_typescript.default.isFunctionDeclaration(statement) && statement.body) {
|
|
947
|
+
if (findJsxReturn(statement.body)) {
|
|
948
|
+
return statement;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (import_typescript.default.isVariableStatement(statement)) {
|
|
952
|
+
for (const decl of statement.declarationList.declarations) {
|
|
953
|
+
const init = decl.initializer;
|
|
954
|
+
if (!init) continue;
|
|
955
|
+
if (import_typescript.default.isArrowFunction(init) || import_typescript.default.isFunctionExpression(init)) {
|
|
956
|
+
if (findJsxInFunctionBody(init.body)) {
|
|
957
|
+
return init;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return null;
|
|
964
|
+
}
|
|
965
|
+
function findJsxReturn(body) {
|
|
966
|
+
for (const statement of body.statements) {
|
|
967
|
+
if (import_typescript.default.isReturnStatement(statement) && statement.expression) {
|
|
968
|
+
const jsx = unwrapJsx(statement.expression);
|
|
969
|
+
if (jsx) {
|
|
970
|
+
return jsx;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
return void 0;
|
|
975
|
+
}
|
|
976
|
+
function findJsxInFunctionBody(body) {
|
|
977
|
+
if (import_typescript.default.isBlock(body)) {
|
|
978
|
+
return findJsxReturn(body);
|
|
979
|
+
}
|
|
980
|
+
return unwrapJsx(body);
|
|
981
|
+
}
|
|
982
|
+
function unwrapJsx(expression) {
|
|
983
|
+
let current = expression;
|
|
984
|
+
while (import_typescript.default.isParenthesizedExpression(current)) {
|
|
985
|
+
current = current.expression;
|
|
986
|
+
}
|
|
987
|
+
if (import_typescript.default.isJsxElement(current) || import_typescript.default.isJsxFragment(current) || import_typescript.default.isJsxSelfClosingElement(current)) {
|
|
988
|
+
return current;
|
|
989
|
+
}
|
|
990
|
+
return void 0;
|
|
991
|
+
}
|
|
992
|
+
function inferScriptKind(filename) {
|
|
993
|
+
const dotIndex = filename.lastIndexOf(".");
|
|
994
|
+
const ext = dotIndex === -1 ? "" : filename.slice(dotIndex).toLowerCase();
|
|
995
|
+
if (ext === ".tsx") return import_typescript.default.ScriptKind.TSX;
|
|
996
|
+
if (ext === ".jsx") return import_typescript.default.ScriptKind.JSX;
|
|
997
|
+
if (ext === ".ts") return import_typescript.default.ScriptKind.TS;
|
|
998
|
+
return import_typescript.default.ScriptKind.JS;
|
|
999
|
+
}
|
|
809
1000
|
function resolveOutputPath2(filepath) {
|
|
810
1001
|
return filepath.replace(/\.[tj]sx?$/, "") + ".collie";
|
|
811
1002
|
}
|
|
@@ -1082,7 +1273,7 @@ async function checkCollieFiles(context) {
|
|
|
1082
1273
|
};
|
|
1083
1274
|
}
|
|
1084
1275
|
async function testCompilation() {
|
|
1085
|
-
const template = ["
|
|
1276
|
+
const template = ["#inputs", " name", "", 'div class="doctor-check"', " h1", " Hello {{ name }}"].join(
|
|
1086
1277
|
"\n"
|
|
1087
1278
|
);
|
|
1088
1279
|
try {
|
|
@@ -2076,30 +2267,30 @@ async function patchViteConfig(configPath) {
|
|
|
2076
2267
|
}
|
|
2077
2268
|
}
|
|
2078
2269
|
function transformViteConfig(source) {
|
|
2079
|
-
const sourceFile =
|
|
2270
|
+
const sourceFile = import_typescript2.default.createSourceFile(
|
|
2080
2271
|
"vite.config.ts",
|
|
2081
2272
|
source,
|
|
2082
|
-
|
|
2273
|
+
import_typescript2.default.ScriptTarget.Latest,
|
|
2083
2274
|
true,
|
|
2084
|
-
|
|
2275
|
+
import_typescript2.default.ScriptKind.TS
|
|
2085
2276
|
);
|
|
2086
2277
|
let needsImport = !source.includes("@collie-lang/vite");
|
|
2087
2278
|
let needsPlugin = !/\bcollie\s*\(/.test(source);
|
|
2088
2279
|
let changed = false;
|
|
2089
|
-
const printer =
|
|
2280
|
+
const printer = import_typescript2.default.createPrinter({ newLine: import_typescript2.default.NewLineKind.LineFeed });
|
|
2090
2281
|
const transformer = (context) => {
|
|
2091
2282
|
return (rootNode) => {
|
|
2092
2283
|
function visit(node) {
|
|
2093
|
-
if (needsImport &&
|
|
2284
|
+
if (needsImport && import_typescript2.default.isImportDeclaration(node)) {
|
|
2094
2285
|
return node;
|
|
2095
2286
|
}
|
|
2096
|
-
if (
|
|
2287
|
+
if (import_typescript2.default.isCallExpression(node) && import_typescript2.default.isIdentifier(node.expression) && node.expression.text === "defineConfig" && node.arguments.length > 0) {
|
|
2097
2288
|
const configArg = node.arguments[0];
|
|
2098
|
-
if (
|
|
2289
|
+
if (import_typescript2.default.isObjectLiteralExpression(configArg)) {
|
|
2099
2290
|
const updatedConfig = updateConfigObject(configArg);
|
|
2100
2291
|
if (updatedConfig !== configArg) {
|
|
2101
2292
|
changed = true;
|
|
2102
|
-
return
|
|
2293
|
+
return import_typescript2.default.factory.updateCallExpression(
|
|
2103
2294
|
node,
|
|
2104
2295
|
node.expression,
|
|
2105
2296
|
node.typeArguments,
|
|
@@ -2108,42 +2299,42 @@ function transformViteConfig(source) {
|
|
|
2108
2299
|
}
|
|
2109
2300
|
}
|
|
2110
2301
|
}
|
|
2111
|
-
return
|
|
2302
|
+
return import_typescript2.default.visitEachChild(node, visit, context);
|
|
2112
2303
|
}
|
|
2113
2304
|
function updateConfigObject(configObj) {
|
|
2114
2305
|
let pluginsProperty;
|
|
2115
2306
|
const otherProperties = [];
|
|
2116
2307
|
for (const prop of configObj.properties) {
|
|
2117
|
-
if (
|
|
2308
|
+
if (import_typescript2.default.isPropertyAssignment(prop) && import_typescript2.default.isIdentifier(prop.name) && prop.name.text === "plugins") {
|
|
2118
2309
|
pluginsProperty = prop;
|
|
2119
2310
|
} else {
|
|
2120
2311
|
otherProperties.push(prop);
|
|
2121
2312
|
}
|
|
2122
2313
|
}
|
|
2123
2314
|
let updatedPluginsArray;
|
|
2124
|
-
if (pluginsProperty &&
|
|
2315
|
+
if (pluginsProperty && import_typescript2.default.isArrayLiteralExpression(pluginsProperty.initializer)) {
|
|
2125
2316
|
updatedPluginsArray = ensurePluginOrdering(pluginsProperty.initializer);
|
|
2126
2317
|
if (updatedPluginsArray === pluginsProperty.initializer) {
|
|
2127
2318
|
return configObj;
|
|
2128
2319
|
}
|
|
2129
2320
|
} else if (needsPlugin) {
|
|
2130
|
-
updatedPluginsArray =
|
|
2321
|
+
updatedPluginsArray = import_typescript2.default.factory.createArrayLiteralExpression(
|
|
2131
2322
|
[createCollieCall()],
|
|
2132
2323
|
false
|
|
2133
2324
|
);
|
|
2134
2325
|
} else {
|
|
2135
2326
|
return configObj;
|
|
2136
2327
|
}
|
|
2137
|
-
const updatedPluginsProperty =
|
|
2328
|
+
const updatedPluginsProperty = import_typescript2.default.factory.createPropertyAssignment(
|
|
2138
2329
|
"plugins",
|
|
2139
2330
|
updatedPluginsArray
|
|
2140
2331
|
);
|
|
2141
2332
|
if (pluginsProperty) {
|
|
2142
2333
|
const allProperties = [...otherProperties, updatedPluginsProperty];
|
|
2143
|
-
return
|
|
2334
|
+
return import_typescript2.default.factory.updateObjectLiteralExpression(configObj, allProperties);
|
|
2144
2335
|
} else {
|
|
2145
2336
|
const allProperties = [...otherProperties, updatedPluginsProperty];
|
|
2146
|
-
return
|
|
2337
|
+
return import_typescript2.default.factory.updateObjectLiteralExpression(configObj, allProperties);
|
|
2147
2338
|
}
|
|
2148
2339
|
}
|
|
2149
2340
|
function ensurePluginOrdering(array) {
|
|
@@ -2153,7 +2344,7 @@ function transformViteConfig(source) {
|
|
|
2153
2344
|
let reactIndex = -1;
|
|
2154
2345
|
let collieIndex = -1;
|
|
2155
2346
|
elements.forEach((elem, idx) => {
|
|
2156
|
-
if (
|
|
2347
|
+
if (import_typescript2.default.isCallExpression(elem) && import_typescript2.default.isIdentifier(elem.expression)) {
|
|
2157
2348
|
if (elem.expression.text === "react") {
|
|
2158
2349
|
hasReact = true;
|
|
2159
2350
|
reactIndex = idx;
|
|
@@ -2169,7 +2360,7 @@ function transformViteConfig(source) {
|
|
|
2169
2360
|
const newElements = [...elements];
|
|
2170
2361
|
const colliePlugin = newElements.splice(collieIndex, 1)[0];
|
|
2171
2362
|
newElements.splice(reactIndex, 0, colliePlugin);
|
|
2172
|
-
return
|
|
2363
|
+
return import_typescript2.default.factory.createArrayLiteralExpression(newElements, isMultiLine);
|
|
2173
2364
|
}
|
|
2174
2365
|
return array;
|
|
2175
2366
|
}
|
|
@@ -2180,31 +2371,31 @@ function transformViteConfig(source) {
|
|
|
2180
2371
|
} else {
|
|
2181
2372
|
newElements.unshift(createCollieCall());
|
|
2182
2373
|
}
|
|
2183
|
-
return
|
|
2374
|
+
return import_typescript2.default.factory.createArrayLiteralExpression(newElements, isMultiLine);
|
|
2184
2375
|
}
|
|
2185
2376
|
return array;
|
|
2186
2377
|
}
|
|
2187
2378
|
function createCollieCall() {
|
|
2188
|
-
return
|
|
2189
|
-
|
|
2379
|
+
return import_typescript2.default.factory.createCallExpression(
|
|
2380
|
+
import_typescript2.default.factory.createIdentifier("collie"),
|
|
2190
2381
|
void 0,
|
|
2191
2382
|
[]
|
|
2192
2383
|
);
|
|
2193
2384
|
}
|
|
2194
|
-
const visited =
|
|
2385
|
+
const visited = import_typescript2.default.visitNode(rootNode, visit);
|
|
2195
2386
|
if (needsImport && changed) {
|
|
2196
|
-
const collieImport =
|
|
2387
|
+
const collieImport = import_typescript2.default.factory.createImportDeclaration(
|
|
2197
2388
|
void 0,
|
|
2198
|
-
|
|
2389
|
+
import_typescript2.default.factory.createImportClause(
|
|
2199
2390
|
false,
|
|
2200
|
-
|
|
2391
|
+
import_typescript2.default.factory.createIdentifier("collie"),
|
|
2201
2392
|
void 0
|
|
2202
2393
|
),
|
|
2203
|
-
|
|
2394
|
+
import_typescript2.default.factory.createStringLiteral("@collie-lang/vite", true)
|
|
2204
2395
|
);
|
|
2205
2396
|
let lastImportIndex = -1;
|
|
2206
2397
|
for (let i = 0; i < visited.statements.length; i++) {
|
|
2207
|
-
if (
|
|
2398
|
+
if (import_typescript2.default.isImportDeclaration(visited.statements[i])) {
|
|
2208
2399
|
lastImportIndex = i;
|
|
2209
2400
|
}
|
|
2210
2401
|
}
|
|
@@ -2214,12 +2405,12 @@ function transformViteConfig(source) {
|
|
|
2214
2405
|
} else {
|
|
2215
2406
|
statements.unshift(collieImport);
|
|
2216
2407
|
}
|
|
2217
|
-
return
|
|
2408
|
+
return import_typescript2.default.factory.updateSourceFile(visited, statements);
|
|
2218
2409
|
}
|
|
2219
2410
|
return visited;
|
|
2220
2411
|
};
|
|
2221
2412
|
};
|
|
2222
|
-
const result =
|
|
2413
|
+
const result = import_typescript2.default.transform(sourceFile, [transformer]);
|
|
2223
2414
|
const transformedSourceFile = result.transformed[0];
|
|
2224
2415
|
result.dispose();
|
|
2225
2416
|
if (!changed) {
|
|
@@ -2233,7 +2424,7 @@ async function ensureCollieDeclaration(root) {
|
|
|
2233
2424
|
if ((0, import_node_fs3.existsSync)(target)) return;
|
|
2234
2425
|
await import_promises8.default.mkdir(import_node_path8.default.dirname(target), { recursive: true });
|
|
2235
2426
|
const declaration = `// Allows importing Collie templates as React components.
|
|
2236
|
-
// Customize this typing if your templates expose specific
|
|
2427
|
+
// Customize this typing if your templates expose specific inputs.
|
|
2237
2428
|
declare module "*.collie" {
|
|
2238
2429
|
import type { ComponentType } from "react";
|
|
2239
2430
|
const component: ComponentType<Record<string, unknown>>;
|