@collie-lang/cli 1.3.3 → 1.5.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/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 import_typescript = __toESM(require("typescript"));
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 { collie, warnings } = result;
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 = ["props", ' name: string = "world"', "", 'div class="doctor-check"', " h1", " Hello {{ name }}"].join(
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 = import_typescript.default.createSourceFile(
2270
+ const sourceFile = import_typescript2.default.createSourceFile(
2080
2271
  "vite.config.ts",
2081
2272
  source,
2082
- import_typescript.default.ScriptTarget.Latest,
2273
+ import_typescript2.default.ScriptTarget.Latest,
2083
2274
  true,
2084
- import_typescript.default.ScriptKind.TS
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 = import_typescript.default.createPrinter({ newLine: import_typescript.default.NewLineKind.LineFeed });
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 && import_typescript.default.isImportDeclaration(node)) {
2284
+ if (needsImport && import_typescript2.default.isImportDeclaration(node)) {
2094
2285
  return node;
2095
2286
  }
2096
- if (import_typescript.default.isCallExpression(node) && import_typescript.default.isIdentifier(node.expression) && node.expression.text === "defineConfig" && node.arguments.length > 0) {
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 (import_typescript.default.isObjectLiteralExpression(configArg)) {
2289
+ if (import_typescript2.default.isObjectLiteralExpression(configArg)) {
2099
2290
  const updatedConfig = updateConfigObject(configArg);
2100
2291
  if (updatedConfig !== configArg) {
2101
2292
  changed = true;
2102
- return import_typescript.default.factory.updateCallExpression(
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 import_typescript.default.visitEachChild(node, visit, context);
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 (import_typescript.default.isPropertyAssignment(prop) && import_typescript.default.isIdentifier(prop.name) && prop.name.text === "plugins") {
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 && import_typescript.default.isArrayLiteralExpression(pluginsProperty.initializer)) {
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 = import_typescript.default.factory.createArrayLiteralExpression(
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 = import_typescript.default.factory.createPropertyAssignment(
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 import_typescript.default.factory.updateObjectLiteralExpression(configObj, allProperties);
2334
+ return import_typescript2.default.factory.updateObjectLiteralExpression(configObj, allProperties);
2144
2335
  } else {
2145
2336
  const allProperties = [...otherProperties, updatedPluginsProperty];
2146
- return import_typescript.default.factory.updateObjectLiteralExpression(configObj, allProperties);
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 (import_typescript.default.isCallExpression(elem) && import_typescript.default.isIdentifier(elem.expression)) {
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 import_typescript.default.factory.createArrayLiteralExpression(newElements, isMultiLine);
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 import_typescript.default.factory.createArrayLiteralExpression(newElements, isMultiLine);
2374
+ return import_typescript2.default.factory.createArrayLiteralExpression(newElements, isMultiLine);
2184
2375
  }
2185
2376
  return array;
2186
2377
  }
2187
2378
  function createCollieCall() {
2188
- return import_typescript.default.factory.createCallExpression(
2189
- import_typescript.default.factory.createIdentifier("collie"),
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 = import_typescript.default.visitNode(rootNode, visit);
2385
+ const visited = import_typescript2.default.visitNode(rootNode, visit);
2195
2386
  if (needsImport && changed) {
2196
- const collieImport = import_typescript.default.factory.createImportDeclaration(
2387
+ const collieImport = import_typescript2.default.factory.createImportDeclaration(
2197
2388
  void 0,
2198
- import_typescript.default.factory.createImportClause(
2389
+ import_typescript2.default.factory.createImportClause(
2199
2390
  false,
2200
- import_typescript.default.factory.createIdentifier("collie"),
2391
+ import_typescript2.default.factory.createIdentifier("collie"),
2201
2392
  void 0
2202
2393
  ),
2203
- import_typescript.default.factory.createStringLiteral("@collie-lang/vite", true)
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 (import_typescript.default.isImportDeclaration(visited.statements[i])) {
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 import_typescript.default.factory.updateSourceFile(visited, statements);
2408
+ return import_typescript2.default.factory.updateSourceFile(visited, statements);
2218
2409
  }
2219
2410
  return visited;
2220
2411
  };
2221
2412
  };
2222
- const result = import_typescript.default.transform(sourceFile, [transformer]);
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 props.
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>>;