Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for a # prefix in path segments #14

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,15 @@ export function preparePath(data, sexpr, parts, loc) {
let depth = 0;

for (let i = 0, l = parts.length; i < l; i++) {
let part = parts[i].part,
// If we have [] syntax then we do not treat path references as operators,
// i.e. foo.[this] resolves to approximately context.foo['this']
isLiteral = parts[i].original !== part;
original += (parts[i].separator || '') + part;
let part = parts[i].part;
// If we have [] syntax then we do not treat path references as operators,
// i.e. foo.[this] resolves to approximately context.foo['this']
let isLiteral = parts[i].original !== part;
let separator = parts[i].separator;

let partPrefix = separator === '.#' ? '#' : '';

original += (separator || '') + part;

if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
if (tail.length > 0) {
Expand All @@ -74,14 +78,15 @@ export function preparePath(data, sexpr, parts, loc) {
depth++;
}
} else {
tail.push(part);
tail.push(`${partPrefix}${part}`);
}
}

let head = sexpr || tail.shift();

return {
type: 'PathExpression',
this: original.startsWith('this.'),
data,
depth,
head,
Expand Down
18 changes: 14 additions & 4 deletions lib/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,29 @@ PrintVisitor.prototype.SubExpression = function(sexpr) {
PrintVisitor.prototype.PathExpression = function(id) {
let head = typeof id.head === 'string' ? id.head : `[${this.accept(id.head)}]`;
let path = [head, ...id.tail].join('/');
return (id.data ? '@' : '') + 'PATH:' + path;
return 'p%' + prefix(id) + path;
};

function prefix(path) {
if (path.data) {
return '@';
} else if (path.this) {
return 'this.';
} else {
return '';
}
}

PrintVisitor.prototype.StringLiteral = function(string) {
return '"' + string.value + '"';
};

PrintVisitor.prototype.NumberLiteral = function(number) {
return 'NUMBER{' + number.value + '}';
return 'n%' + number.value;
};

PrintVisitor.prototype.BooleanLiteral = function(bool) {
return 'BOOLEAN{' + bool.value + '}';
return 'b%' + bool.value;
};

PrintVisitor.prototype.UndefinedLiteral = function() {
Expand All @@ -171,7 +181,7 @@ PrintVisitor.prototype.Hash = function(hash) {
joinedPairs.push(this.accept(pairs[i]));
}

return 'HASH{' + joinedPairs.join(', ') + '}';
return 'HASH{' + joinedPairs.join(' ') + '}';
};
PrintVisitor.prototype.HashPair = function(pair) {
return pair.key + '=' + this.accept(pair.value);
Expand Down
235 changes: 235 additions & 0 deletions lib/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
export interface BaseNode {
type: string;
loc: SourceLocation;
}

export interface InverseChain {
strip: StripFlags;
program: Program;
chain?: boolean;
}

export interface Program {
type: 'Program';
/**
* The root node of a program has no `loc` if it's empty.
*/
loc: SourceLocation | undefined;
blockParams?: string[];
body: Statement[];
chained?: boolean;
strip: StripFlags;
}

export interface CommentStatement extends BaseNode {
type: 'CommentStatement';
value: string;
strip: StripFlags;
}

export interface PartialStatement extends BaseNode {
type: 'PartialStatement';
name: Expression;
params: Expression[];
hash: Hash;
indent: string;
strip: StripFlags;
}

export interface BlockStatement extends BaseNode {
type: 'BlockStatement';
path: Expression;
params: Expression[];
hash: Hash;
program: Program | undefined;
inverse?: Program | undefined;
openStrip: StripFlags;
inverseStrip: StripFlags | undefined;
closeStrip: StripFlags;
}

export interface DecoratorBlock extends BaseNode {
type: 'DecoratorBlock';
path: Expression;
params: Expression[];
hash: Hash;
program: Program;
inverse?: undefined;
inverseStrip?: undefined;
openStrip: StripFlags;
closeStrip: StripFlags;
}

export interface PartialBlockStatement extends BaseNode {
type: 'PartialBlockStatement';
name: Expression;
params: Expression[];
hash: Hash;
program: Program;
inverse?: undefined;
inverseStrip?: undefined;
openStrip: StripFlags;
closeStrip: StripFlags;
}

export type Statement =
| MustacheStatement
| Content
| BlockStatement
| PartialStatement
| PartialBlockStatement;

export interface MustacheStatement extends BaseNode {
type: 'Decorator' | 'MustacheStatement';
path: Expression;
params: Expression[];
hash: Hash;
escaped: boolean;
strip: StripFlags;
}

export interface PathExpression extends BaseNode {
readonly original: string;
readonly this: boolean;
readonly data: boolean;
readonly depth: number;
readonly parts: (string | SubExpression)[];
readonly head: string | SubExpression | undefined;
readonly tail: string[];
}

export interface SubExpression extends BaseNode {
readonly original: string;
}

export interface Hash {
readonly pairs: HashPair[];
}

export interface StripFlags {
readonly open?: boolean;
readonly close?: boolean;
readonly openStandalone?: boolean;
readonly closeStandalone?: boolean;
readonly inlineStandalone?: boolean;
}

export interface HashPair {
readonly key: string;
readonly value: Expression;
}

export interface ParserPart {
readonly part: string;
readonly original: string;
readonly separator: string;
}

export interface Content extends BaseNode {
type: 'ContentStatement';
original: string;
value: string;
}

export type Expression = SubExpression | PathExpression;

export interface SourcePosition {
line: number;
column: number;
}

export interface SourceLocation {
source: string | undefined;
start: SourcePosition;
end: SourcePosition;
}

export interface CallNode {
path: Expression;
params: Expression[];
hash: Hash;
}

export interface OpenPartial {
strip: StripFlags;
}

export interface OpenPartialBlock extends CallNode {
strip: StripFlags;
}

export interface OpenRawBlock extends CallNode, BaseNode {}

export interface OpenBlock extends CallNode {
open: string;
blockParams: string[];
strip: StripFlags;
}

export interface OpenInverse extends CallNode {
blockParams: string[];
strip: StripFlags;
}

export interface CloseBlock {
readonly path: PathExpression;
strip: StripFlags;
}

export type AcceptedNode = Program;

/// JISON TYPES ///

export interface Parser {
parse: (input: string) => Program;
yy: YY;
}

export interface YY {
locInfo(locInfo: LocInfo): SourceLocation;
preparePath(
this: YY,
data: boolean,
sexpr: { expr: SubExpression; sep: string } | false,
parts: ParserPart[],
locInfo: LocInfo,
): PathExpression;

prepareMustache(
this: YY,
path: PathExpression,
params: Expression[],
hash: Hash,
open: string,
strip: StripFlags,
locInfo: LocInfo,
): MustacheStatement;

prepareRawBlock(
this: YY,
openRawBlock: OpenRawBlock,
contents: Content[],
close: string,
locInfo: LocInfo,
): BlockStatement;

prepareBlock(
this: YY,
openBlock: OpenBlock,
program: Program,
inverseChain: InverseChain,
close: CloseBlock,
inverted: boolean,
locInfo: LocInfo,
): BlockStatement | DecoratorBlock;
}

/**
* The `LocInfo` object comes from the generated `jison` parser.
*/
export interface LocInfo {
first_line: number;
first_column: number;
last_line: number;
last_column: number;
}
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@
},
"devDependencies": {
"combine-files": "^1.1.8",
"eslint": "^7.8.1",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-compat": "^3.8.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^8.10.0",
"eslint-plugin-compat": "^3.13.0",
"esm": "^3.2.25",
"jison": "^0.4.18",
"mocha": "^8.1.3",
"npm-run-all": "^4.1.5",
"prettier": "^2.1.1",
"release-it": "^14.0.2",
"release-it-lerna-changelog": "^2.4.0",
"typescript": "^4.0.2"
"typescript": "^5.6.3"
},
"publishConfig": {
"access": "public",
Expand Down
Loading
Loading