semantifold 0.6.0 → 0.8.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.
Files changed (41) hide show
  1. package/README.md +8 -4
  2. package/build/index.d.ts +8 -8
  3. package/build/index.d.ts.map +1 -1
  4. package/build/index.js +6 -6
  5. package/build/src/backends/android.js +2 -2
  6. package/build/src/backends/dart.d.ts +19 -0
  7. package/build/src/backends/dart.d.ts.map +1 -1
  8. package/build/src/backends/dart.js +28 -16
  9. package/build/src/backends/flutter.d.ts +51 -0
  10. package/build/src/backends/flutter.d.ts.map +1 -0
  11. package/build/src/backends/flutter.js +1362 -0
  12. package/build/src/backends/identifiers.js +5 -5
  13. package/build/src/backends/program.d.ts +4 -4
  14. package/build/src/backends/program.d.ts.map +1 -1
  15. package/build/src/backends/program.js +4 -4
  16. package/build/src/backends/shared.d.ts +7 -0
  17. package/build/src/backends/shared.d.ts.map +1 -1
  18. package/build/src/backends/shared.js +11 -6
  19. package/build/src/language-registry.d.ts.map +1 -1
  20. package/build/src/language-registry.js +11 -1
  21. package/build/src/semantic/types.d.ts +152 -2
  22. package/build/src/semantic/types.d.ts.map +1 -1
  23. package/build/src/semantic/types.js +38 -2
  24. package/docs/android.md +6 -2
  25. package/docs/architecture.md +2 -0
  26. package/docs/flutter.md +47 -0
  27. package/docs/goals.md +1 -1
  28. package/docs/language-support.md +9 -2
  29. package/docs/source-maps.md +2 -0
  30. package/docs/testing.md +22 -1
  31. package/docs/watch-build-pipeline.md +154 -0
  32. package/index.js +5 -5
  33. package/package.json +1 -1
  34. package/src/backends/android.js +1 -1
  35. package/src/backends/dart.js +28 -15
  36. package/src/backends/flutter.js +1465 -0
  37. package/src/backends/identifiers.js +4 -4
  38. package/src/backends/program.js +3 -3
  39. package/src/backends/shared.js +12 -8
  40. package/src/language-registry.js +10 -0
  41. package/src/semantic/types.js +40 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {unsupportedCapability} from "../diagnostic.js"
4
4
 
5
- /** @type {Record<Exclude<import("../semantic/types.js").BackendLanguage, "ios">, RegExp>} */
5
+ /** @type {Record<Exclude<import("../semantic/types.js").BackendLanguage, "ios" | "flutter">, RegExp>} */
6
6
  const identifierPatterns = {
7
7
  android: /^(?:_|\p{L})(?:_|\p{L}|\p{Nd})*$/u,
8
8
  dart: /^(?:_|\p{L})(?:_|\p{L}|\p{Nd})*$/u,
@@ -23,7 +23,7 @@ const identifierPatterns = {
23
23
  wasm: /^(?:[$_]|\p{XID_Start})(?:[$_]|\p{XID_Continue})*$/u
24
24
  }
25
25
 
26
- /** @type {Record<Exclude<import("../semantic/types.js").BackendLanguage, "ios">, Set<string>>} */
26
+ /** @type {Record<Exclude<import("../semantic/types.js").BackendLanguage, "ios" | "flutter">, Set<string>>} */
27
27
  const reservedWords = {
28
28
  android: new Set([
29
29
  "as", "break", "class", "continue", "do", "else", "false", "for", "fun", "if", "in", "interface", "is", "null",
@@ -236,7 +236,7 @@ export function validateTargetIdentifier(language, name, role, location) {
236
236
  if (typeof name != "string") unsupportedCapability(language, `${role} identifier`, location)
237
237
 
238
238
  const reservedName = language == "php" ? name.toLowerCase() : name
239
- const syntaxLanguage = language == "ios" ? "swift" : language
239
+ const syntaxLanguage = language == "ios" ? "swift" : language == "flutter" ? "dart" : language
240
240
 
241
241
  if (!identifierPatterns[syntaxLanguage].test(name) || reservedWords[syntaxLanguage].has(reservedName) ||
242
242
  language == "python" && name.normalize("NFKC") != name ||
@@ -296,7 +296,7 @@ export function validateTargetTypeIdentifier(language, name, location) {
296
296
  unsupportedCapability(language, `record type identifier '${String(name)}'`, location)
297
297
  }
298
298
  const reservedName = language == "php" ? name.toLowerCase() : name
299
- const syntaxLanguage = language == "ios" ? "swift" : language
299
+ const syntaxLanguage = language == "ios" ? "swift" : language == "flutter" ? "dart" : language
300
300
 
301
301
  if (reservedWords[syntaxLanguage].has(reservedName) || reservedTypeNames[language]?.has(reservedName)) {
302
302
  unsupportedCapability(language, `record type identifier '${name}'`, location)
@@ -23,7 +23,7 @@ import {programImportName, SourceWriter} from "./writer.js"
23
23
  /** @type {Readonly<Set<import("../semantic/types.js").SemanticLanguage>>} */
24
24
  const programTargets = new Set(["php", "ruby", "javascript", "typescript", "java"])
25
25
  /** @type {Readonly<Set<import("../semantic/types.js").BackendLanguage>>} */
26
- const programApplicationTargets = new Set(["android", "ios"])
26
+ const programApplicationTargets = new Set(["android", "ios", "flutter"])
27
27
 
28
28
  /**
29
29
  * Validates and prepares a complete semantic program for a non-text backend without allocating a writer.
@@ -68,8 +68,8 @@ export function preflightSemanticProgram({backendLanguage, diagnosticLanguage, p
68
68
  * @param {import("../semantic/types.js").BackendLanguage} input.language - Registered program target.
69
69
  * @param {import("../semantic/types.js").SemanticProgram} input.program - Complete semantic program.
70
70
  * @param {"text" | "application"} [input.role] - Explicit artifact role; omitted preserves text generation.
71
- * @param {import("../semantic/types.js").IosApplicationConfigurationInput | import("../semantic/types.js").AndroidApplicationConfigurationInput} [input.configuration] - Application configuration.
72
- * @param {import("../semantic/types.js").IosApplicationAssetInput[] | import("../semantic/types.js").AndroidApplicationInputFile[]} [input.assets] - Exact caller assets.
71
+ * @param {import("../semantic/types.js").IosApplicationConfigurationInput | import("../semantic/types.js").AndroidApplicationConfigurationInput | import("../semantic/types.js").FlutterApplicationConfigurationInput} [input.configuration] - Application configuration.
72
+ * @param {import("../semantic/types.js").IosApplicationAssetInput[] | import("../semantic/types.js").AndroidApplicationInputFile[] | import("../semantic/types.js").FlutterApplicationAssetInput[]} [input.assets] - Exact caller assets.
73
73
  * @param {import("../semantic/types.js").AndroidApplicationInputFile[]} [input.resources] - Exact Android caller resources.
74
74
  * @returns {import("../semantic/types.js").GeneratedArtifactSet} Transactionally validated artifact set.
75
75
  */
@@ -2241,7 +2241,8 @@ export function emitExpression(writer, expression, path, language, emitIdentifie
2241
2241
  return
2242
2242
  }
2243
2243
  if (expression.kind == "CallExpression") {
2244
- const dartMultiline = language == "dart" && expression.arguments.length > 0 &&
2244
+ const callArgumentSuffix = writer.callArgumentSuffixFor(expression)
2245
+ const dartMultiline = language == "dart" && (expression.arguments.length > 0 || Boolean(callArgumentSuffix)) &&
2245
2246
  dartExpressionExceedsPageWidth(writer, expression)
2246
2247
  const dartIndent = dartMultiline ? currentLineIndent(writer) : ""
2247
2248
 
@@ -2255,11 +2256,10 @@ export function emitExpression(writer, expression, path, language, emitIdentifie
2255
2256
  emitExpression(writer, argument, `${path}/arguments/${index}`, language, emitIdentifier)
2256
2257
  if (dartMultiline) writer.synthetic(",\n", "Dart formatter argument separator", [expression], [path])
2257
2258
  })
2258
- const callArgumentSuffix = writer.callArgumentSuffixFor(expression)
2259
-
2260
2259
  if (callArgumentSuffix) {
2261
- writer.synthetic(`${expression.arguments.length ? ", " : ""}${callArgumentSuffix}`,
2262
- "target-container semantic call argument", [expression], [path])
2260
+ writer.synthetic(dartMultiline ? `${expression.arguments.length ? "" : "\n"}${dartIndent} ${callArgumentSuffix},\n` :
2261
+ `${expression.arguments.length ? ", " : ""}${callArgumentSuffix}`,
2262
+ "target-container semantic call argument", [expression], [path])
2263
2263
  }
2264
2264
  if (dartMultiline) writer.synthetic(dartIndent, "Dart call closing indentation", [expression], [path])
2265
2265
  writer.mapped(")", {mappingKind: "anchor", node: expression, path})
@@ -2558,14 +2558,18 @@ function currentLineIndent(writer) {
2558
2558
  * @param {import("../semantic/types.js").Expression} expression Semantic expression.
2559
2559
  * @returns {string} Flat canonical spelling.
2560
2560
  */
2561
- function flatDartExpression(writer, expression) {
2561
+ export function flatDartExpression(writer, expression) {
2562
2562
  if (expression.kind == "IdentifierExpression") return expression.name
2563
2563
  if (expression.kind == "IntegerLiteral") return String(expression.value)
2564
2564
  if (expression.kind == "BooleanLiteral") return `_semantifoldBoolean(${expression.value ? "true" : "false"})`
2565
2565
  if (expression.kind == "StringLiteral") return emitStringLiteral("dart", expression.value)
2566
2566
  if (expression.kind == "CallExpression") {
2567
- return `${writer.callNameFor(expression)}(${expression.arguments.map((argument) =>
2568
- flatDartExpression(writer, argument)).join(", ")})`
2567
+ const arguments_ = expression.arguments.map((argument) => flatDartExpression(writer, argument))
2568
+ const callArgumentSuffix = writer.callArgumentSuffixFor(expression)
2569
+
2570
+ if (callArgumentSuffix) arguments_.push(callArgumentSuffix)
2571
+
2572
+ return `${writer.callNameFor(expression)}(${arguments_.join(", ")})`
2569
2573
  }
2570
2574
  if (expression.kind == "UnaryExpression") {
2571
2575
  const operand = flatDartExpression(writer, expression.operand)
@@ -18,6 +18,7 @@ import {generateTypeScript} from "./backends/typescript.js"
18
18
  import {generateBrowserWasm} from "./backends/wasm.js"
19
19
  import {generateIosApplication} from "./backends/ios.js"
20
20
  import {generateAndroidApplication} from "./backends/android.js"
21
+ import {generateFlutterApplication} from "./backends/flutter.js"
21
22
  import {parseJava} from "./frontends/java.js"
22
23
  import {parseKotlin} from "./frontends/kotlin.js"
23
24
  import {parseCSharp} from "./frontends/csharp.js"
@@ -549,6 +550,15 @@ const records = [
549
550
  id: "ios",
550
551
  mapping: {binaryRanges: true, richText: true, sourceMapV3: true},
551
552
  roundTrip: false
553
+ },
554
+ {
555
+ acceptance: {stages: ["generate", "restore", "compile", "validate", "instantiate", "execute"], toolchains: ["flutter", "android"]},
556
+ applicationBackend: generateFlutterApplication,
557
+ artifactMultiplicity: "multiple",
558
+ features: {closedRecords: false, conditionControlledLoops: false, effectfulCapabilitiesAndResources: false, generalFunctionsAndCalls: false, immutableCollections: false, optionalValues: false, orderedListIteration: false, orderedMapIteration: false, referenceClasses: false, typedErrors: false, typeParametersAndGenerics: false},
559
+ id: "flutter",
560
+ mapping: {binaryRanges: true, richText: true, sourceMapV3: true},
561
+ roundTrip: false
552
562
  }
553
563
  ]
554
564
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  /** @typedef {"php" | "ruby" | "javascript" | "typescript" | "java" | "kotlin" | "python" | "csharp" | "go" | "c" | "cpp" | "rust" | "swift" | "dart" | "zig"} SemanticLanguage */
4
4
  /** @typedef {SemanticLanguage} TextBackendLanguage */
5
- /** @typedef {TextBackendLanguage | "wasm" | "ios" | "android"} BackendLanguage */
5
+ /** @typedef {TextBackendLanguage | "wasm" | "ios" | "android" | "flutter"} BackendLanguage */
6
6
  /** @typedef {SemanticLanguage | "html"} GeneratedTextLanguage */
7
7
  /** @typedef {"integer" | "boolean" | "string"} SemanticTypeName */
8
8
  /** @typedef {SemanticTypeName | "void"} FunctionReturnTypeName */
@@ -103,6 +103,45 @@
103
103
  * @property {string} sha256 - Lowercase SHA-256 of exact UTF-8 text or bytes.
104
104
  */
105
105
 
106
+ /**
107
+ * @typedef FlutterApplicationConfigurationInput
108
+ * @property {string} [packageName] - Lowercase Dart package identity.
109
+ * @property {string} [organization] - Lowercase reverse-DNS owning organization.
110
+ * @property {string} [applicationId] - Lowercase reverse-DNS Android application identity extending the organization.
111
+ * @property {string} [activityClassName] - Generated Java launcher Activity class name.
112
+ * @property {string} [displayName] - User-visible application label.
113
+ * @property {23} [minimumSdk] - Qualified minimum Android API.
114
+ * @property {35} [targetSdk] - Qualified target Android API.
115
+ * @property {35} [compileSdk] - Qualified compile Android API.
116
+ * @property {"35.0.0"} [buildToolsVersion] - Qualified Android Build Tools version.
117
+ * @property {number} [versionCode] - Positive Android/Flutter build number.
118
+ * @property {string} [versionName] - Canonical application version name.
119
+ * @property {unknown[]} [permissions] - Validated as the closed empty permission set.
120
+ */
121
+
122
+ /**
123
+ * @typedef FlutterApplicationConfiguration
124
+ * @property {string} packageName - Validated Dart package identity.
125
+ * @property {string} organization - Validated owning organization.
126
+ * @property {string} applicationId - Validated Android application identity.
127
+ * @property {string} activityClassName - Generated Java launcher Activity class name.
128
+ * @property {string} displayName - User-visible application label.
129
+ * @property {23} minimumSdk - Qualified minimum Android API.
130
+ * @property {35} targetSdk - Qualified target Android API.
131
+ * @property {35} compileSdk - Qualified compile Android API.
132
+ * @property {"35.0.0"} buildToolsVersion - Qualified Android Build Tools version.
133
+ * @property {number} versionCode - Positive Android/Flutter build number.
134
+ * @property {string} versionName - Canonical application version name.
135
+ */
136
+
137
+ /**
138
+ * @typedef FlutterApplicationAssetInput
139
+ * @property {string} path - Safe path below the generated Flutter assets root.
140
+ * @property {string | Uint8Array} content - Exact caller-provided text or bytes.
141
+ * @property {string} mediaType - Explicit artifact media type.
142
+ * @property {string} sha256 - Lowercase SHA-256 of exact UTF-8 text or bytes.
143
+ */
144
+
106
145
  /**
107
146
  * @typedef LanguageRoleCapabilities
108
147
  * @property {boolean} frontend - Parser adapter availability.