@anvil-works/anvil-cli 0.8.0-canary.3 → 0.8.0-canary.5

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.
@@ -1 +1 @@
1
- {"version":3,"file":"SavePathRouter.d.ts","sourceRoot":"","sources":["../src/SavePathRouter.ts"],"names":[],"mappings":"AAMA,OAAO,EAGH,KAAK,uBAAuB,EAE/B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAmB,MAAM,cAAc,CAAC;AAMlE,KAAK,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;AAG3B,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,MAAM,QAAQ,GAAG,uBAAuB,CAAC;AAE/C,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AASD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhE,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjH,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAwWD;;;GAGG;AACH,wBAAgB,sBAAsB,CAClC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9F,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgEtF;AAED,wBAAsB,eAAe,CACjC,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,YAAY,GACtB,OAAO,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC,CAqBpC;AA8zBD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACrC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAC1C,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC,CAiE7C"}
1
+ {"version":3,"file":"SavePathRouter.d.ts","sourceRoot":"","sources":["../src/SavePathRouter.ts"],"names":[],"mappings":"AAMA,OAAO,EAGH,KAAK,uBAAuB,EAE/B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAmB,MAAM,cAAc,CAAC;AAMlE,KAAK,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;AAG3B,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AACD,MAAM,MAAM,QAAQ,GAAG,uBAAuB,CAAC;AAE/C,MAAM,WAAW,SAAS;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACnB;AASD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhE,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,GAAG,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjH,MAAM,WAAW,YAAY;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAwWD;;;GAGG;AACH,wBAAgB,sBAAsB,CAClC,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC9F,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgEtF;AAED,wBAAsB,eAAe,CACjC,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,YAAY,GACtB,OAAO,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC,CAqBpC;AAq1BD;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACrC,QAAQ,EAAE,MAAM,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAC1C,OAAO,CAAC,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC,CAiE7C"}
package/dist/cli.js CHANGED
@@ -14996,15 +14996,11 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
14996
14996
  }
14997
14997
  }
14998
14998
  async mergeFastForward(ref) {
14999
- try {
15000
- await this.git.raw([
14999
+ await this.runGitCommandWithIndexLockRetry("merge --ff-only", ()=>this.git.raw([
15001
15000
  "merge",
15002
15001
  "--ff-only",
15003
15002
  ref
15004
- ]);
15005
- } catch (e) {
15006
- throw errors_createGitError.commandFailed("merge --ff-only", e.message);
15007
- }
15003
+ ]));
15008
15004
  }
15009
15005
  async deleteRef(ref) {
15010
15006
  try {
@@ -15863,7 +15859,8 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
15863
15859
  if (PYTHON_KEYWORDS.has(value)) pushIssue(issues, path, "must be a valid Python identifier (not a keyword)");
15864
15860
  }
15865
15861
  const componentTypeSpec_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
15866
- const DEP_ID_RE = /^dep_[A-Za-z0-9]+$/;
15862
+ const LEGACY_CUSTOM_COMPONENT_SPEC_RE = /^form:(?:([^:]+):)?(.+)$/;
15863
+ const PACKAGE_QUALIFIED_FORM_NAME_RE = /^([^.]+)\.(.+)$/;
15867
15864
  const componentTypeSpec_PYTHON_KEYWORDS = new Set([
15868
15865
  "False",
15869
15866
  "None",
@@ -15903,32 +15900,17 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
15903
15900
  "match",
15904
15901
  "case"
15905
15902
  ]);
15906
- const LEGACY_FORM_TYPE_REFERENCE_MESSAGE = "must be a valid form: reference (form:Module.Form, form:dep_xxx:Package.Form)";
15903
+ const LEGACY_FORM_TYPE_REFERENCE_MESSAGE = "must be a valid form: reference (form:Module.Form, form:dep_xxx:Package.Form, form:APP_ID:Package.Form)";
15907
15904
  const COMPONENT_TYPE_REFERENCE_MESSAGE = "must be a known Anvil component type (see componentIcons.ts), a form: reference, or a package-qualified form reference (Package.Form)";
15908
15905
  function isValidIdentifierSegment(value) {
15909
15906
  return value.length > 0 && componentTypeSpec_IDENTIFIER_RE.test(value) && !componentTypeSpec_PYTHON_KEYWORDS.has(value);
15910
15907
  }
15911
15908
  function isValidLegacyFormTypeReference(typeName) {
15912
- if (!typeName.startsWith("form:")) return false;
15913
- const rest = typeName.slice(5);
15914
- if (0 === rest.length) return false;
15915
- let classPath = rest;
15916
- if (rest.startsWith("dep_")) {
15917
- const splitIndex = rest.indexOf(":");
15918
- if (splitIndex <= 0) return false;
15919
- const depId = rest.slice(0, splitIndex);
15920
- if (!DEP_ID_RE.test(depId)) return false;
15921
- classPath = rest.slice(splitIndex + 1);
15922
- }
15923
- if (0 === classPath.length) return false;
15924
- return classPath.split(".").every((part)=>isValidIdentifierSegment(part));
15909
+ return LEGACY_CUSTOM_COMPONENT_SPEC_RE.test(typeName);
15925
15910
  }
15926
15911
  function isValidPackageQualifiedComponentType(typeName) {
15927
15912
  if (typeName.startsWith("anvil.")) return false;
15928
- if (!typeName.includes(".")) return false;
15929
- const parts = typeName.split(".");
15930
- if (parts.length < 2) return false;
15931
- return parts.every((part)=>isValidIdentifierSegment(part));
15913
+ return PACKAGE_QUALIFIED_FORM_NAME_RE.test(typeName);
15932
15914
  }
15933
15915
  function componentTypeSpec_pushIssue(issues, path, message) {
15934
15916
  issues.push({
@@ -16037,7 +16019,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
16037
16019
  const bindingPath = `${path}[${index}]`;
16038
16020
  if (!isPlainObject(binding)) return void formTemplateValidation_pushIssue(issues, bindingPath, "must be an object");
16039
16021
  if ("string" != typeof binding.property || 0 === binding.property.length) formTemplateValidation_pushIssue(issues, `${bindingPath}.property`, "must be a non-empty string");
16040
- if ("string" != typeof binding.code || 0 === binding.code.length) formTemplateValidation_pushIssue(issues, `${bindingPath}.code`, "must be a non-empty string");
16022
+ if ("string" != typeof binding.code) formTemplateValidation_pushIssue(issues, `${bindingPath}.code`, "must be a string");
16041
16023
  if (void 0 !== binding.writeback && "boolean" != typeof binding.writeback) formTemplateValidation_pushIssue(issues, `${bindingPath}.writeback`, "must be a boolean");
16042
16024
  });
16043
16025
  }
@@ -17911,7 +17893,7 @@ print(json.dumps({"issues": issues}))
17911
17893
  ]
17912
17894
  });
17913
17895
  }
17914
- async function buildFormTemplateData(relativePath, templateInfo, context) {
17896
+ async function buildFormTemplateData(relativePath, templateInfo, context, missingCodeBehavior = "error") {
17915
17897
  const { repoPath, stagedOnly = false } = context;
17916
17898
  const { kind } = templateInfo;
17917
17899
  const loadResult = await loadFormTemplateData(relativePath, templateInfo, context);
@@ -17925,15 +17907,28 @@ print(json.dumps({"issues": issues}))
17925
17907
  };
17926
17908
  const codeRelativePath = "package" === kind ? relativePath.replace(/form_template\.(yaml|html)$/i, "__init__.py") : relativePath.replace(/\.(yaml|html)$/i, ".py");
17927
17909
  const className = extractPythonName(codeRelativePath);
17928
- const codeContent = await readFileContent(repoPath, codeRelativePath, stagedOnly);
17929
- if (!codeContent) return {
17930
- formData: {},
17931
- className: "",
17932
- ignoreResult: {
17933
- type: "ignore",
17934
- reason: "package" === kind ? "Form __init__.py file not found - cannot save template without code" : "Form .py file not found - cannot save template without code"
17910
+ let codeContent;
17911
+ try {
17912
+ codeContent = await readFileContent(repoPath, codeRelativePath, stagedOnly);
17913
+ } catch (error) {
17914
+ if (stagedOnly || !isFileNotFoundError(error) || "error" === missingCodeBehavior) throw error;
17915
+ const missingCodeReason = `Form code file ${codeRelativePath} is not present yet`;
17916
+ const knownForm = context.editorYaml.hasId("forms", className);
17917
+ if ("defer" === missingCodeBehavior || knownForm) {
17918
+ const action = knownForm ? `not saving existing form ${className}` : `deferring form ${className}`;
17919
+ logger_logger.warn(external_chalk_default().yellow(`Form template ${relativePath} has no code file ${codeRelativePath} yet; ${action}.`));
17920
+ return {
17921
+ formData: {},
17922
+ className: "",
17923
+ ignoreResult: {
17924
+ type: "ignore",
17925
+ reason: missingCodeReason
17926
+ }
17927
+ };
17935
17928
  }
17936
- };
17929
+ codeContent = "";
17930
+ logger_logger.warn(external_chalk_default().yellow(`Form template ${relativePath} has no code file ${codeRelativePath} yet; creating ${className} with empty code.`));
17931
+ }
17937
17932
  const formData = (0, form_template_parser_namespaceObject.buildFormTemplateSavePayload)(loadResult.source, {
17938
17933
  className,
17939
17934
  code: codeContent,
@@ -17945,6 +17940,9 @@ print(json.dumps({"issues": issues}))
17945
17940
  ignoreResult: null
17946
17941
  };
17947
17942
  }
17943
+ function isFileNotFoundError(error) {
17944
+ return "object" == typeof error && null !== error && "ENOENT" === error.code;
17945
+ }
17948
17946
  async function handleFormTemplateChange(change, context) {
17949
17947
  const { editorYaml } = context;
17950
17948
  const { relativePath, changeType } = change;
@@ -17955,10 +17953,11 @@ print(json.dumps({"issues": issues}))
17955
17953
  };
17956
17954
  const kind = templateInfo.kind;
17957
17955
  const format = templateInfo.format;
17956
+ const missingCodeBehavior = "add" === changeType ? "create-new-form-if-unknown" : "defer";
17958
17957
  const result = await buildFormTemplateData(relativePath, {
17959
17958
  kind,
17960
17959
  format
17961
- }, context);
17960
+ }, context, missingCodeBehavior);
17962
17961
  if (result.ignoreResult) return result.ignoreResult;
17963
17962
  const { formData, className } = result;
17964
17963
  return handleIdBasedOperation({
@@ -18244,10 +18243,13 @@ print(json.dumps({"issues": issues}))
18244
18243
  code: error.type,
18245
18244
  recoverability: "requires_user_action",
18246
18245
  requiresUserAction: true,
18247
- suggestedAction: "Inspect the repository state and resolve the Git error before retrying.",
18246
+ suggestedAction: isIndexLockFailure(error) ? "Confirm no Git process is running for this repository, then remove the stale .git/index.lock file and retry." : "Inspect the repository state and resolve the Git error before retrying.",
18248
18247
  gitCommand: "git_command_failed" === error.type ? error.command : void 0
18249
18248
  };
18250
18249
  }
18250
+ function isIndexLockFailure(error) {
18251
+ return "git_command_failed" === error.type && error.message.includes("Unable to create") && error.message.includes("index.lock") && error.message.includes("File exists");
18252
+ }
18251
18253
  function networkDiagnostic(error) {
18252
18254
  return {
18253
18255
  code: error.type,
@@ -1,5 +1,5 @@
1
1
  import type { ValidationIssue } from "./validators";
2
- export declare const LEGACY_FORM_TYPE_REFERENCE_MESSAGE = "must be a valid form: reference (form:Module.Form, form:dep_xxx:Package.Form)";
2
+ export declare const LEGACY_FORM_TYPE_REFERENCE_MESSAGE = "must be a valid form: reference (form:Module.Form, form:dep_xxx:Package.Form, form:APP_ID:Package.Form)";
3
3
  export declare const COMPONENT_TYPE_REFERENCE_MESSAGE = "must be a known Anvil component type (see componentIcons.ts), a form: reference, or a package-qualified form reference (Package.Form)";
4
4
  export declare function isValidLegacyFormTypeReference(typeName: string): boolean;
5
5
  export declare function isValidPackageQualifiedComponentType(typeName: string): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"componentTypeSpec.d.ts","sourceRoot":"","sources":["../src/componentTypeSpec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AA6CpD,eAAO,MAAM,kCAAkC,kFACoC,CAAC;AAEpF,eAAO,MAAM,gCAAgC,0IAC8F,CAAC;AAM5I,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CA0BxE;AAED,wBAAgB,oCAAoC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAY9E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAWlH;AAMD,wBAAgB,yBAAyB,CACrC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EAAE,EACzB,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAAC,QAwBjD"}
1
+ {"version":3,"file":"componentTypeSpec.d.ts","sourceRoot":"","sources":["../src/componentTypeSpec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AA8CpD,eAAO,MAAM,kCAAkC,4GAC8D,CAAC;AAE9G,eAAO,MAAM,gCAAgC,0IAC8F,CAAC;AAM5I,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExE;AAED,wBAAgB,oCAAoC,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAK9E;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,OAAO,CAWlH;AAMD,wBAAgB,yBAAyB,CACrC,KAAK,EAAE,OAAO,EACd,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EAAE,EACzB,yBAAyB,EAAE,WAAW,CAAC,MAAM,CAAC,QAwBjD"}
package/dist/index.js CHANGED
@@ -15025,15 +15025,11 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
15025
15025
  }
15026
15026
  }
15027
15027
  async mergeFastForward(ref) {
15028
- try {
15029
- await this.git.raw([
15028
+ await this.runGitCommandWithIndexLockRetry("merge --ff-only", ()=>this.git.raw([
15030
15029
  "merge",
15031
15030
  "--ff-only",
15032
15031
  ref
15033
- ]);
15034
- } catch (e) {
15035
- throw errors_createGitError.commandFailed("merge --ff-only", e.message);
15036
- }
15032
+ ]));
15037
15033
  }
15038
15034
  async deleteRef(ref) {
15039
15035
  try {
@@ -15892,7 +15888,8 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
15892
15888
  if (PYTHON_KEYWORDS.has(value)) pushIssue(issues, path, "must be a valid Python identifier (not a keyword)");
15893
15889
  }
15894
15890
  const componentTypeSpec_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
15895
- const DEP_ID_RE = /^dep_[A-Za-z0-9]+$/;
15891
+ const LEGACY_CUSTOM_COMPONENT_SPEC_RE = /^form:(?:([^:]+):)?(.+)$/;
15892
+ const PACKAGE_QUALIFIED_FORM_NAME_RE = /^([^.]+)\.(.+)$/;
15896
15893
  const componentTypeSpec_PYTHON_KEYWORDS = new Set([
15897
15894
  "False",
15898
15895
  "None",
@@ -15932,32 +15929,17 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
15932
15929
  "match",
15933
15930
  "case"
15934
15931
  ]);
15935
- const LEGACY_FORM_TYPE_REFERENCE_MESSAGE = "must be a valid form: reference (form:Module.Form, form:dep_xxx:Package.Form)";
15932
+ const LEGACY_FORM_TYPE_REFERENCE_MESSAGE = "must be a valid form: reference (form:Module.Form, form:dep_xxx:Package.Form, form:APP_ID:Package.Form)";
15936
15933
  const COMPONENT_TYPE_REFERENCE_MESSAGE = "must be a known Anvil component type (see componentIcons.ts), a form: reference, or a package-qualified form reference (Package.Form)";
15937
15934
  function isValidIdentifierSegment(value) {
15938
15935
  return value.length > 0 && componentTypeSpec_IDENTIFIER_RE.test(value) && !componentTypeSpec_PYTHON_KEYWORDS.has(value);
15939
15936
  }
15940
15937
  function isValidLegacyFormTypeReference(typeName) {
15941
- if (!typeName.startsWith("form:")) return false;
15942
- const rest = typeName.slice(5);
15943
- if (0 === rest.length) return false;
15944
- let classPath = rest;
15945
- if (rest.startsWith("dep_")) {
15946
- const splitIndex = rest.indexOf(":");
15947
- if (splitIndex <= 0) return false;
15948
- const depId = rest.slice(0, splitIndex);
15949
- if (!DEP_ID_RE.test(depId)) return false;
15950
- classPath = rest.slice(splitIndex + 1);
15951
- }
15952
- if (0 === classPath.length) return false;
15953
- return classPath.split(".").every((part)=>isValidIdentifierSegment(part));
15938
+ return LEGACY_CUSTOM_COMPONENT_SPEC_RE.test(typeName);
15954
15939
  }
15955
15940
  function isValidPackageQualifiedComponentType(typeName) {
15956
15941
  if (typeName.startsWith("anvil.")) return false;
15957
- if (!typeName.includes(".")) return false;
15958
- const parts = typeName.split(".");
15959
- if (parts.length < 2) return false;
15960
- return parts.every((part)=>isValidIdentifierSegment(part));
15942
+ return PACKAGE_QUALIFIED_FORM_NAME_RE.test(typeName);
15961
15943
  }
15962
15944
  function componentTypeSpec_pushIssue(issues, path, message) {
15963
15945
  issues.push({
@@ -16066,7 +16048,7 @@ Promise.resolve(executeGitCredentialOperation(process.argv[2] || "get", {
16066
16048
  const bindingPath = `${path}[${index}]`;
16067
16049
  if (!isPlainObject(binding)) return void formTemplateValidation_pushIssue(issues, bindingPath, "must be an object");
16068
16050
  if ("string" != typeof binding.property || 0 === binding.property.length) formTemplateValidation_pushIssue(issues, `${bindingPath}.property`, "must be a non-empty string");
16069
- if ("string" != typeof binding.code || 0 === binding.code.length) formTemplateValidation_pushIssue(issues, `${bindingPath}.code`, "must be a non-empty string");
16051
+ if ("string" != typeof binding.code) formTemplateValidation_pushIssue(issues, `${bindingPath}.code`, "must be a string");
16070
16052
  if (void 0 !== binding.writeback && "boolean" != typeof binding.writeback) formTemplateValidation_pushIssue(issues, `${bindingPath}.writeback`, "must be a boolean");
16071
16053
  });
16072
16054
  }
@@ -17940,7 +17922,7 @@ print(json.dumps({"issues": issues}))
17940
17922
  ]
17941
17923
  });
17942
17924
  }
17943
- async function buildFormTemplateData(relativePath, templateInfo, context) {
17925
+ async function buildFormTemplateData(relativePath, templateInfo, context, missingCodeBehavior = "error") {
17944
17926
  const { repoPath, stagedOnly = false } = context;
17945
17927
  const { kind } = templateInfo;
17946
17928
  const loadResult = await loadFormTemplateData(relativePath, templateInfo, context);
@@ -17954,15 +17936,28 @@ print(json.dumps({"issues": issues}))
17954
17936
  };
17955
17937
  const codeRelativePath = "package" === kind ? relativePath.replace(/form_template\.(yaml|html)$/i, "__init__.py") : relativePath.replace(/\.(yaml|html)$/i, ".py");
17956
17938
  const className = extractPythonName(codeRelativePath);
17957
- const codeContent = await readFileContent(repoPath, codeRelativePath, stagedOnly);
17958
- if (!codeContent) return {
17959
- formData: {},
17960
- className: "",
17961
- ignoreResult: {
17962
- type: "ignore",
17963
- reason: "package" === kind ? "Form __init__.py file not found - cannot save template without code" : "Form .py file not found - cannot save template without code"
17939
+ let codeContent;
17940
+ try {
17941
+ codeContent = await readFileContent(repoPath, codeRelativePath, stagedOnly);
17942
+ } catch (error) {
17943
+ if (stagedOnly || !isFileNotFoundError(error) || "error" === missingCodeBehavior) throw error;
17944
+ const missingCodeReason = `Form code file ${codeRelativePath} is not present yet`;
17945
+ const knownForm = context.editorYaml.hasId("forms", className);
17946
+ if ("defer" === missingCodeBehavior || knownForm) {
17947
+ const action = knownForm ? `not saving existing form ${className}` : `deferring form ${className}`;
17948
+ logger_logger.warn(external_chalk_default().yellow(`Form template ${relativePath} has no code file ${codeRelativePath} yet; ${action}.`));
17949
+ return {
17950
+ formData: {},
17951
+ className: "",
17952
+ ignoreResult: {
17953
+ type: "ignore",
17954
+ reason: missingCodeReason
17955
+ }
17956
+ };
17964
17957
  }
17965
- };
17958
+ codeContent = "";
17959
+ logger_logger.warn(external_chalk_default().yellow(`Form template ${relativePath} has no code file ${codeRelativePath} yet; creating ${className} with empty code.`));
17960
+ }
17966
17961
  const formData = (0, form_template_parser_namespaceObject.buildFormTemplateSavePayload)(loadResult.source, {
17967
17962
  className,
17968
17963
  code: codeContent,
@@ -17974,6 +17969,9 @@ print(json.dumps({"issues": issues}))
17974
17969
  ignoreResult: null
17975
17970
  };
17976
17971
  }
17972
+ function isFileNotFoundError(error) {
17973
+ return "object" == typeof error && null !== error && "ENOENT" === error.code;
17974
+ }
17977
17975
  async function handleFormTemplateChange(change, context) {
17978
17976
  const { editorYaml } = context;
17979
17977
  const { relativePath, changeType } = change;
@@ -17984,10 +17982,11 @@ print(json.dumps({"issues": issues}))
17984
17982
  };
17985
17983
  const kind = templateInfo.kind;
17986
17984
  const format = templateInfo.format;
17985
+ const missingCodeBehavior = "add" === changeType ? "create-new-form-if-unknown" : "defer";
17987
17986
  const result = await buildFormTemplateData(relativePath, {
17988
17987
  kind,
17989
17988
  format
17990
- }, context);
17989
+ }, context, missingCodeBehavior);
17991
17990
  if (result.ignoreResult) return result.ignoreResult;
17992
17991
  const { formData, className } = result;
17993
17992
  return handleIdBasedOperation({
@@ -18273,10 +18272,13 @@ print(json.dumps({"issues": issues}))
18273
18272
  code: error.type,
18274
18273
  recoverability: "requires_user_action",
18275
18274
  requiresUserAction: true,
18276
- suggestedAction: "Inspect the repository state and resolve the Git error before retrying.",
18275
+ suggestedAction: isIndexLockFailure(error) ? "Confirm no Git process is running for this repository, then remove the stale .git/index.lock file and retry." : "Inspect the repository state and resolve the Git error before retrying.",
18277
18276
  gitCommand: "git_command_failed" === error.type ? error.command : void 0
18278
18277
  };
18279
18278
  }
18279
+ function isIndexLockFailure(error) {
18280
+ return "git_command_failed" === error.type && error.message.includes("Unable to create") && error.message.includes("index.lock") && error.message.includes("File exists");
18281
+ }
18280
18282
  function networkDiagnostic(error) {
18281
18283
  return {
18282
18284
  code: error.type,
@@ -1 +1 @@
1
- {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../src/services/git.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anvil-works/anvil-cli",
3
- "version": "0.8.0-canary.3",
3
+ "version": "0.8.0-canary.5",
4
4
  "description": "CLI tool for developing Anvil apps locally",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/api.d.ts",