@mapled/cli 0.12.0 → 0.14.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/scan.d.ts CHANGED
@@ -61,7 +61,7 @@ export declare function detectRoutes(files: string[], framework: string | null):
61
61
  name; `unclosed`: a quoted string a line break (or the end) cut off
62
62
  before its closing quote — JSX lets an attribute run on. */
63
63
  export type Token = {
64
- kind: "ident" | "string" | "punct";
64
+ kind: "ident" | "string" | "punct" | "regex";
65
65
  value: string;
66
66
  nl?: true;
67
67
  escaped?: true;
@@ -71,8 +71,13 @@ export type Token = {
71
71
  comments and template bodies dropped. A regex literal after an
72
72
  operator is skipped — only one that closes on its line, and never the
73
73
  `/>` after a JSX attribute's `}`; JSX text is read as code, so an apostrophe in
74
- prose can swallow a stretch — a false negative, never a crash. */
75
- export declare function tokenize(text: string): Token[];
74
+ prose can swallow a stretch — a false negative, never a crash.
75
+ `hidden`, when given, gets the code of each template's `${…}`, which
76
+ the tokens leave out; `ambiguous`, where a `/` right after `}` was read
77
+ as a regex — after an object, JavaScript reads a division there, and
78
+ what follows is code (`{} / f(x) / 1`). With `regexes`, a regex is a
79
+ token of its own rather than skipped. */
80
+ export declare function tokenize(text: string, hidden?: string[], ambiguous?: number[], regexes?: boolean): Token[];
76
81
  export declare function routeKey(route: string): string;
77
82
  export declare function scanRepository(dir: string, opts: ScanOptions): Promise<ScanResult>;
78
83
  export type MergeResult = {
package/dist/scan.js CHANGED
@@ -813,12 +813,69 @@ function unescapeAt(text, at) {
813
813
  return [String.fromCharCode(parseInt(octal[0], 8)), at + 1 + octal[0].length];
814
814
  return [e, at + 2];
815
815
  }
816
+ /** The index of the `}` that closes the template substitution whose code
817
+ starts at `from`, with strings, templates and comments in it read as
818
+ JavaScript reads them — `${"}"}` closes at the second brace; the end of
819
+ the text when nothing closes it. A `/` in it that starts no comment may
820
+ start a regex, which can hold a brace or a quote: `doubt` hears of it. */
821
+ function substitutionEnd(text, from, doubt) {
822
+ // what the scan is in: code with that many open braces, or a template's text (0), innermost last
823
+ const stack = [1];
824
+ for (let j = from; j < text.length; j++) {
825
+ const c = text[j];
826
+ const top = stack[stack.length - 1];
827
+ if (top === 0) {
828
+ if (c === "\\")
829
+ j++;
830
+ else if (c === "`")
831
+ stack.pop();
832
+ else if (c === "$" && text[j + 1] === "{") {
833
+ stack.push(1);
834
+ j++;
835
+ }
836
+ }
837
+ else if (c === "{")
838
+ stack[stack.length - 1] = top + 1;
839
+ else if (c === "}") {
840
+ if (top > 1)
841
+ stack[stack.length - 1] = top - 1;
842
+ else {
843
+ stack.pop();
844
+ if (stack.length === 0)
845
+ return j;
846
+ }
847
+ }
848
+ else if (c === '"' || c === "'") {
849
+ for (j++; j < text.length && text[j] !== c && text[j] !== "\n" && text[j] !== "\r"; j++)
850
+ if (text[j] === "\\")
851
+ j++;
852
+ }
853
+ else if (c === "`")
854
+ stack.push(0);
855
+ else if (c === "/" && text[j + 1] === "/") {
856
+ while (j + 1 < text.length && text[j + 1] !== "\n" && text[j + 1] !== "\r")
857
+ j++;
858
+ }
859
+ else if (c === "/" && text[j + 1] === "*") {
860
+ const end = text.indexOf("*/", j + 2);
861
+ j = end === -1 ? text.length : end + 1;
862
+ }
863
+ else if (c === "/")
864
+ doubt?.();
865
+ }
866
+ return text.length;
867
+ }
816
868
  /** JavaScript tokens: identifiers, string literals and punctuation, with
817
869
  comments and template bodies dropped. A regex literal after an
818
870
  operator is skipped — only one that closes on its line, and never the
819
871
  `/>` after a JSX attribute's `}`; JSX text is read as code, so an apostrophe in
820
- prose can swallow a stretch — a false negative, never a crash. */
821
- export function tokenize(text) {
872
+ prose can swallow a stretch — a false negative, never a crash.
873
+ `hidden`, when given, gets the code of each template's `${…}`, which
874
+ the tokens leave out; `ambiguous`, where a `/` right after `}` was read
875
+ as a regex — after an object, JavaScript reads a division there, and
876
+ what follows is code (`{} / f(x) / 1`). With `regexes`, a regex is a
877
+ token of its own rather than skipped. */
878
+ export function tokenize(text, hidden, ambiguous, regexes = false) {
822
879
  const out = [];
823
880
  let i = 0;
824
881
  const n = text.length;
@@ -864,16 +921,11 @@ export function tokenize(text) {
864
921
  continue;
865
922
  }
866
923
  if (c === "`" && text[j] === "$" && text[j + 1] === "{") {
867
- // a substitution: skip to its closing brace (one level)
868
- let depth = 1;
869
- j += 2;
870
- while (j < n && depth > 0) {
871
- if (text[j] === "{")
872
- depth++;
873
- else if (text[j] === "}")
874
- depth--;
875
- j++;
876
- }
924
+ // a substitution: its code, to the brace that closes it as JavaScript reads it
925
+ const from = j + 2;
926
+ const end = substitutionEnd(text, from, ambiguous ? () => ambiguous.push(from) : undefined);
927
+ hidden?.push(text.slice(from, end));
928
+ j = end + 1;
877
929
  value += "${}";
878
930
  continue;
879
931
  }
@@ -932,9 +984,13 @@ export function tokenize(text) {
932
984
  }
933
985
  // a regex closes on its own line; a `/` that doesn't is the code's
934
986
  if (text[j] === "/") {
987
+ if (prev?.kind === "punct" && prev.value === "}")
988
+ ambiguous?.push(i);
935
989
  j++;
936
990
  while (j < n && /[a-z]/.test(text[j]))
937
991
  j++; // flags
992
+ if (regexes)
993
+ push({ kind: "regex", value: text.slice(i, j) });
938
994
  i = j;
939
995
  continue;
940
996
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapled/cli",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Mapled CLI — sign in, link a project, generate TypeScript types for its content, create forms, preview drafts and check the site's integration.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://mapled.io",